From 9c5adaeebbda97de767a990f583360da51b54201 Mon Sep 17 00:00:00 2001 From: Joshua Bahirvani Date: Sun, 6 Sep 2026 02:13:09 +0530 Subject: [PATCH] drift-dataset-codeexec-platform --- .../versionized_gt/D1/README.md | 144 ++++ .../versionized_gt/D1/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/D1/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../D1/commits/C1/cdk/package.json | 15 + .../D1/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/D1/commits/C1/commit.json | 26 + .../versionized_gt/D1/commits/C1/diff.patch | 0 .../versionized_gt/D1/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/D1/commits/C2/cdk/cdk.ts | 409 ++++++++++++ .../D1/commits/C2/cdk/package.json | 15 + .../D1/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/D1/commits/C2/commit.json | 20 + .../versionized_gt/D1/commits/C2/diff.patch | 13 + .../versionized_gt/D1/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/D1/commits/C3/cdk/cdk.ts | 425 ++++++++++++ .../D1/commits/C3/cdk/package.json | 15 + .../D1/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/D1/commits/C3/commit.json | 20 + .../versionized_gt/D1/commits/C3/diff.patch | 27 + .../versionized_gt/D1/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/D1/commits/C4/cdk/cdk.ts | 427 ++++++++++++ .../D1/commits/C4/cdk/package.json | 15 + .../D1/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/D1/commits/C4/commit.json | 20 + .../versionized_gt/D1/commits/C4/diff.patch | 13 + .../versionized_gt/D1/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/D1/commits/C5/cdk/cdk.ts | 432 ++++++++++++ .../D1/commits/C5/cdk/package.json | 15 + .../D1/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/D1/commits/C5/commit.json | 20 + .../versionized_gt/D1/commits/C5/diff.patch | 16 + .../versionized_gt/D1/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/D1/commits/C6/cdk/cdk.ts | 432 ++++++++++++ .../D1/commits/C6/cdk/package.json | 15 + .../D1/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/D1/commits/C6/commit.json | 20 + .../versionized_gt/D1/commits/C6/diff.patch | 13 + .../versionized_gt/D1/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/D1/commits/C7/cdk/cdk.ts | 432 ++++++++++++ .../D1/commits/C7/cdk/package.json | 15 + .../D1/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/D1/commits/C7/commit.json | 20 + .../versionized_gt/D1/commits/C7/diff.patch | 13 + .../versionized_gt/D1/commits/provenance.json | 107 +++ .../versionized_gt/D1/metadata.yaml | 121 ++++ .../versionized_gt/D1/repository | 1 + .../versionized_gt/D1/synth_context.json | 1 + .../versionized_gt/D1/template_analysis.json | 314 +++++++++ .../versionized_gt/D2/README.md | 153 +++++ .../versionized_gt/D2/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../D2/commits/C1/cdk/package.json | 15 + .../D2/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C1/commit.json | 26 + .../versionized_gt/D2/commits/C1/diff.patch | 0 .../D2/commits/C10/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C10/cdk/cdk.ts | 419 ++++++++++++ .../D2/commits/C10/cdk/package.json | 15 + .../D2/commits/C10/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C10/commit.json | 20 + .../versionized_gt/D2/commits/C10/diff.patch | 11 + .../versionized_gt/D2/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C2/cdk/cdk.ts | 409 ++++++++++++ .../D2/commits/C2/cdk/package.json | 15 + .../D2/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C2/commit.json | 20 + .../versionized_gt/D2/commits/C2/diff.patch | 13 + .../versionized_gt/D2/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C3/cdk/cdk.ts | 411 ++++++++++++ .../D2/commits/C3/cdk/package.json | 15 + .../D2/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C3/commit.json | 20 + .../versionized_gt/D2/commits/C3/diff.patch | 13 + .../versionized_gt/D2/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C4/cdk/cdk.ts | 413 ++++++++++++ .../D2/commits/C4/cdk/package.json | 15 + .../D2/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C4/commit.json | 20 + .../versionized_gt/D2/commits/C4/diff.patch | 13 + .../versionized_gt/D2/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C5/cdk/cdk.ts | 418 ++++++++++++ .../D2/commits/C5/cdk/package.json | 15 + .../D2/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C5/commit.json | 20 + .../versionized_gt/D2/commits/C5/diff.patch | 16 + .../versionized_gt/D2/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C6/cdk/cdk.ts | 418 ++++++++++++ .../D2/commits/C6/cdk/package.json | 15 + .../D2/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C6/commit.json | 20 + .../versionized_gt/D2/commits/C6/diff.patch | 15 + .../versionized_gt/D2/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C7/cdk/cdk.ts | 418 ++++++++++++ .../D2/commits/C7/cdk/package.json | 15 + .../D2/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C7/commit.json | 20 + .../versionized_gt/D2/commits/C7/diff.patch | 13 + .../versionized_gt/D2/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C8/cdk/cdk.ts | 419 ++++++++++++ .../D2/commits/C8/cdk/package.json | 15 + .../D2/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C8/commit.json | 20 + .../versionized_gt/D2/commits/C8/diff.patch | 12 + .../versionized_gt/D2/commits/C9/cdk/cdk.json | 89 +++ .../versionized_gt/D2/commits/C9/cdk/cdk.ts | 419 ++++++++++++ .../D2/commits/C9/cdk/package.json | 15 + .../D2/commits/C9/cdk/tsconfig.json | 15 + .../versionized_gt/D2/commits/C9/commit.json | 20 + .../versionized_gt/D2/commits/C9/diff.patch | 13 + .../versionized_gt/D2/commits/provenance.json | 152 +++++ .../versionized_gt/D2/metadata.yaml | 149 +++++ .../versionized_gt/D2/repository | 1 + .../versionized_gt/D2/synth_context.json | 1 + .../versionized_gt/D2/template_analysis.json | 446 +++++++++++++ .../versionized_gt/D3/README.md | 159 +++++ .../versionized_gt/D3/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../D3/commits/C1/cdk/package.json | 15 + .../D3/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C1/commit.json | 26 + .../versionized_gt/D3/commits/C1/diff.patch | 0 .../D3/commits/C10/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C10/cdk/cdk.ts | 435 ++++++++++++ .../D3/commits/C10/cdk/package.json | 15 + .../D3/commits/C10/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C10/commit.json | 20 + .../versionized_gt/D3/commits/C10/diff.patch | 13 + .../D3/commits/C11/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C11/cdk/cdk.ts | 435 ++++++++++++ .../D3/commits/C11/cdk/package.json | 15 + .../D3/commits/C11/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C11/commit.json | 20 + .../versionized_gt/D3/commits/C11/diff.patch | 13 + .../D3/commits/C12/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C12/cdk/cdk.ts | 435 ++++++++++++ .../D3/commits/C12/cdk/package.json | 15 + .../D3/commits/C12/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C12/commit.json | 20 + .../versionized_gt/D3/commits/C12/diff.patch | 11 + .../versionized_gt/D3/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C2/cdk/cdk.ts | 409 ++++++++++++ .../D3/commits/C2/cdk/package.json | 15 + .../D3/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C2/commit.json | 20 + .../versionized_gt/D3/commits/C2/diff.patch | 13 + .../versionized_gt/D3/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C3/cdk/cdk.ts | 411 ++++++++++++ .../D3/commits/C3/cdk/package.json | 15 + .../D3/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C3/commit.json | 20 + .../versionized_gt/D3/commits/C3/diff.patch | 13 + .../versionized_gt/D3/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C4/cdk/cdk.ts | 411 ++++++++++++ .../D3/commits/C4/cdk/package.json | 15 + .../D3/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C4/commit.json | 20 + .../versionized_gt/D3/commits/C4/diff.patch | 15 + .../versionized_gt/D3/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C5/cdk/cdk.ts | 413 ++++++++++++ .../D3/commits/C5/cdk/package.json | 15 + .../D3/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C5/commit.json | 20 + .../versionized_gt/D3/commits/C5/diff.patch | 13 + .../versionized_gt/D3/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C6/cdk/cdk.ts | 418 ++++++++++++ .../D3/commits/C6/cdk/package.json | 15 + .../D3/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C6/commit.json | 20 + .../versionized_gt/D3/commits/C6/diff.patch | 16 + .../versionized_gt/D3/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C7/cdk/cdk.ts | 434 ++++++++++++ .../D3/commits/C7/cdk/package.json | 15 + .../D3/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C7/commit.json | 20 + .../versionized_gt/D3/commits/C7/diff.patch | 27 + .../versionized_gt/D3/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C8/cdk/cdk.ts | 435 ++++++++++++ .../D3/commits/C8/cdk/package.json | 15 + .../D3/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C8/commit.json | 20 + .../versionized_gt/D3/commits/C8/diff.patch | 12 + .../versionized_gt/D3/commits/C9/cdk/cdk.json | 89 +++ .../versionized_gt/D3/commits/C9/cdk/cdk.ts | 435 ++++++++++++ .../D3/commits/C9/cdk/package.json | 15 + .../D3/commits/C9/cdk/tsconfig.json | 15 + .../versionized_gt/D3/commits/C9/commit.json | 20 + .../versionized_gt/D3/commits/C9/diff.patch | 12 + .../versionized_gt/D3/commits/provenance.json | 182 +++++ .../versionized_gt/D3/metadata.yaml | 167 +++++ .../versionized_gt/D3/repository | 1 + .../versionized_gt/D3/synth_context.json | 1 + .../versionized_gt/D3/template_analysis.json | 534 +++++++++++++++ .../versionized_gt/D4/README.md | 138 ++++ .../versionized_gt/D4/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/D4/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../D4/commits/C1/cdk/package.json | 15 + .../D4/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/D4/commits/C1/commit.json | 26 + .../versionized_gt/D4/commits/C1/diff.patch | 0 .../versionized_gt/D4/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/D4/commits/C2/cdk/cdk.ts | 414 ++++++++++++ .../D4/commits/C2/cdk/package.json | 15 + .../D4/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/D4/commits/C2/commit.json | 20 + .../versionized_gt/D4/commits/C2/diff.patch | 16 + .../versionized_gt/D4/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/D4/commits/C3/cdk/cdk.ts | 416 ++++++++++++ .../D4/commits/C3/cdk/package.json | 15 + .../D4/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/D4/commits/C3/commit.json | 20 + .../versionized_gt/D4/commits/C3/diff.patch | 13 + .../versionized_gt/D4/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/D4/commits/C4/cdk/cdk.ts | 416 ++++++++++++ .../D4/commits/C4/cdk/package.json | 15 + .../D4/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/D4/commits/C4/commit.json | 20 + .../versionized_gt/D4/commits/C4/diff.patch | 13 + .../versionized_gt/D4/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/D4/commits/C5/cdk/cdk.ts | 416 ++++++++++++ .../D4/commits/C5/cdk/package.json | 15 + .../D4/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/D4/commits/C5/commit.json | 20 + .../versionized_gt/D4/commits/C5/diff.patch | 13 + .../versionized_gt/D4/commits/provenance.json | 77 +++ .../versionized_gt/D4/metadata.yaml | 104 +++ .../versionized_gt/D4/repository | 1 + .../versionized_gt/D4/synth_context.json | 1 + .../versionized_gt/D4/template_analysis.json | 226 +++++++ .../versionized_gt/E1/README.md | 136 ++++ .../versionized_gt/E1/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/E1/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../E1/commits/C1/cdk/package.json | 15 + .../E1/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/E1/commits/C1/commit.json | 26 + .../versionized_gt/E1/commits/C1/diff.patch | 0 .../versionized_gt/E1/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/E1/commits/C2/cdk/cdk.ts | 412 ++++++++++++ .../E1/commits/C2/cdk/package.json | 15 + .../E1/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/E1/commits/C2/commit.json | 20 + .../versionized_gt/E1/commits/C2/diff.patch | 16 + .../versionized_gt/E1/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/E1/commits/C3/cdk/cdk.ts | 417 ++++++++++++ .../E1/commits/C3/cdk/package.json | 15 + .../E1/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/E1/commits/C3/commit.json | 20 + .../versionized_gt/E1/commits/C3/diff.patch | 16 + .../versionized_gt/E1/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/E1/commits/C4/cdk/cdk.ts | 417 ++++++++++++ .../E1/commits/C4/cdk/package.json | 15 + .../E1/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/E1/commits/C4/commit.json | 20 + .../versionized_gt/E1/commits/C4/diff.patch | 16 + .../versionized_gt/E1/commits/provenance.json | 62 ++ .../versionized_gt/E1/metadata.yaml | 99 +++ .../versionized_gt/E1/repository | 1 + .../versionized_gt/E1/synth_context.json | 1 + .../versionized_gt/E1/template_analysis.json | 182 +++++ .../versionized_gt/E2/README.md | 144 ++++ .../versionized_gt/E2/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/E2/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../E2/commits/C1/cdk/package.json | 15 + .../E2/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/E2/commits/C1/commit.json | 26 + .../versionized_gt/E2/commits/C1/diff.patch | 0 .../versionized_gt/E2/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/E2/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../E2/commits/C2/cdk/package.json | 15 + .../E2/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/E2/commits/C2/commit.json | 20 + .../versionized_gt/E2/commits/C2/diff.patch | 12 + .../versionized_gt/E2/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/E2/commits/C3/cdk/cdk.ts | 418 ++++++++++++ .../E2/commits/C3/cdk/package.json | 15 + .../E2/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/E2/commits/C3/commit.json | 20 + .../versionized_gt/E2/commits/C3/diff.patch | 19 + .../versionized_gt/E2/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/E2/commits/C4/cdk/cdk.ts | 423 ++++++++++++ .../E2/commits/C4/cdk/package.json | 15 + .../E2/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/E2/commits/C4/commit.json | 20 + .../versionized_gt/E2/commits/C4/diff.patch | 16 + .../versionized_gt/E2/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/E2/commits/C5/cdk/cdk.ts | 423 ++++++++++++ .../E2/commits/C5/cdk/package.json | 15 + .../E2/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/E2/commits/C5/commit.json | 20 + .../versionized_gt/E2/commits/C5/diff.patch | 13 + .../versionized_gt/E2/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/E2/commits/C6/cdk/cdk.ts | 423 ++++++++++++ .../E2/commits/C6/cdk/package.json | 15 + .../E2/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/E2/commits/C6/commit.json | 20 + .../versionized_gt/E2/commits/C6/diff.patch | 13 + .../versionized_gt/E2/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/E2/commits/C7/cdk/cdk.ts | 423 ++++++++++++ .../E2/commits/C7/cdk/package.json | 15 + .../E2/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/E2/commits/C7/commit.json | 20 + .../versionized_gt/E2/commits/C7/diff.patch | 13 + .../versionized_gt/E2/commits/provenance.json | 107 +++ .../versionized_gt/E2/metadata.yaml | 121 ++++ .../versionized_gt/E2/repository | 1 + .../versionized_gt/E2/synth_context.json | 1 + .../versionized_gt/E2/template_analysis.json | 314 +++++++++ .../versionized_gt/E3/README.md | 142 ++++ .../versionized_gt/E3/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/E3/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../E3/commits/C1/cdk/package.json | 15 + .../E3/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/E3/commits/C1/commit.json | 26 + .../versionized_gt/E3/commits/C1/diff.patch | 0 .../versionized_gt/E3/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/E3/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../E3/commits/C2/cdk/package.json | 15 + .../E3/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/E3/commits/C2/commit.json | 20 + .../versionized_gt/E3/commits/C2/diff.patch | 12 + .../versionized_gt/E3/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/E3/commits/C3/cdk/cdk.ts | 415 ++++++++++++ .../E3/commits/C3/cdk/package.json | 15 + .../E3/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/E3/commits/C3/commit.json | 20 + .../versionized_gt/E3/commits/C3/diff.patch | 16 + .../versionized_gt/E3/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/E3/commits/C4/cdk/cdk.ts | 415 ++++++++++++ .../E3/commits/C4/cdk/package.json | 15 + .../E3/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/E3/commits/C4/commit.json | 20 + .../versionized_gt/E3/commits/C4/diff.patch | 13 + .../versionized_gt/E3/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/E3/commits/C5/cdk/cdk.ts | 415 ++++++++++++ .../E3/commits/C5/cdk/package.json | 15 + .../E3/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/E3/commits/C5/commit.json | 20 + .../versionized_gt/E3/commits/C5/diff.patch | 13 + .../versionized_gt/E3/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/E3/commits/C6/cdk/cdk.ts | 415 ++++++++++++ .../E3/commits/C6/cdk/package.json | 15 + .../E3/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/E3/commits/C6/commit.json | 20 + .../versionized_gt/E3/commits/C6/diff.patch | 13 + .../versionized_gt/E3/commits/provenance.json | 92 +++ .../versionized_gt/E3/metadata.yaml | 113 ++++ .../versionized_gt/E3/repository | 1 + .../versionized_gt/E3/synth_context.json | 1 + .../versionized_gt/E3/template_analysis.json | 270 ++++++++ .../versionized_gt/E4/README.md | 163 +++++ .../versionized_gt/E4/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../E4/commits/C1/cdk/package.json | 15 + .../E4/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C1/commit.json | 26 + .../versionized_gt/E4/commits/C1/diff.patch | 0 .../E4/commits/C10/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C10/cdk/cdk.ts | 414 ++++++++++++ .../E4/commits/C10/cdk/package.json | 15 + .../E4/commits/C10/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C10/commit.json | 20 + .../versionized_gt/E4/commits/C10/diff.patch | 15 + .../E4/commits/C11/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C11/cdk/cdk.ts | 414 ++++++++++++ .../E4/commits/C11/cdk/package.json | 15 + .../E4/commits/C11/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C11/commit.json | 20 + .../versionized_gt/E4/commits/C11/diff.patch | 13 + .../E4/commits/C12/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C12/cdk/cdk.ts | 414 ++++++++++++ .../E4/commits/C12/cdk/package.json | 15 + .../E4/commits/C12/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C12/commit.json | 20 + .../versionized_gt/E4/commits/C12/diff.patch | 11 + .../E4/commits/C13/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C13/cdk/cdk.ts | 414 ++++++++++++ .../E4/commits/C13/cdk/package.json | 15 + .../E4/commits/C13/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C13/commit.json | 20 + .../versionized_gt/E4/commits/C13/diff.patch | 13 + .../versionized_gt/E4/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../E4/commits/C2/cdk/package.json | 15 + .../E4/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C2/commit.json | 20 + .../versionized_gt/E4/commits/C2/diff.patch | 12 + .../versionized_gt/E4/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C3/cdk/cdk.ts | 410 ++++++++++++ .../E4/commits/C3/cdk/package.json | 15 + .../E4/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C3/commit.json | 20 + .../versionized_gt/E4/commits/C3/diff.patch | 13 + .../versionized_gt/E4/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C4/cdk/cdk.ts | 412 ++++++++++++ .../E4/commits/C4/cdk/package.json | 15 + .../E4/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C4/commit.json | 20 + .../versionized_gt/E4/commits/C4/diff.patch | 13 + .../versionized_gt/E4/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C5/cdk/cdk.ts | 412 ++++++++++++ .../E4/commits/C5/cdk/package.json | 15 + .../E4/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C5/commit.json | 20 + .../versionized_gt/E4/commits/C5/diff.patch | 15 + .../versionized_gt/E4/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C6/cdk/cdk.ts | 412 ++++++++++++ .../E4/commits/C6/cdk/package.json | 15 + .../E4/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C6/commit.json | 20 + .../versionized_gt/E4/commits/C6/diff.patch | 13 + .../versionized_gt/E4/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C7/cdk/cdk.ts | 417 ++++++++++++ .../E4/commits/C7/cdk/package.json | 15 + .../E4/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C7/commit.json | 20 + .../versionized_gt/E4/commits/C7/diff.patch | 16 + .../versionized_gt/E4/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C8/cdk/cdk.ts | 418 ++++++++++++ .../E4/commits/C8/cdk/package.json | 15 + .../E4/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C8/commit.json | 20 + .../versionized_gt/E4/commits/C8/diff.patch | 12 + .../versionized_gt/E4/commits/C9/cdk/cdk.json | 89 +++ .../versionized_gt/E4/commits/C9/cdk/cdk.ts | 418 ++++++++++++ .../E4/commits/C9/cdk/package.json | 15 + .../E4/commits/C9/cdk/tsconfig.json | 15 + .../versionized_gt/E4/commits/C9/commit.json | 20 + .../versionized_gt/E4/commits/C9/diff.patch | 12 + .../versionized_gt/E4/commits/provenance.json | 197 ++++++ .../versionized_gt/E4/metadata.yaml | 179 +++++ .../versionized_gt/E4/repository | 1 + .../versionized_gt/E4/synth_context.json | 1 + .../versionized_gt/E4/template_analysis.json | 578 ++++++++++++++++ .../versionized_gt/G1/README.md | 147 +++++ .../versionized_gt/G1/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/G1/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../G1/commits/C1/cdk/package.json | 15 + .../G1/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/G1/commits/C1/commit.json | 26 + .../versionized_gt/G1/commits/C1/diff.patch | 0 .../versionized_gt/G1/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/G1/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../G1/commits/C2/cdk/package.json | 15 + .../G1/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/G1/commits/C2/commit.json | 20 + .../versionized_gt/G1/commits/C2/diff.patch | 12 + .../versionized_gt/G1/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/G1/commits/C3/cdk/cdk.ts | 410 ++++++++++++ .../G1/commits/C3/cdk/package.json | 15 + .../G1/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/G1/commits/C3/commit.json | 20 + .../versionized_gt/G1/commits/C3/diff.patch | 13 + .../versionized_gt/G1/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/G1/commits/C4/cdk/cdk.ts | 411 ++++++++++++ .../G1/commits/C4/cdk/package.json | 15 + .../G1/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/G1/commits/C4/commit.json | 20 + .../versionized_gt/G1/commits/C4/diff.patch | 12 + .../versionized_gt/G1/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/G1/commits/C5/cdk/cdk.ts | 416 ++++++++++++ .../G1/commits/C5/cdk/package.json | 15 + .../G1/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/G1/commits/C5/commit.json | 20 + .../versionized_gt/G1/commits/C5/diff.patch | 16 + .../versionized_gt/G1/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/G1/commits/C6/cdk/cdk.ts | 421 ++++++++++++ .../G1/commits/C6/cdk/package.json | 15 + .../G1/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/G1/commits/C6/commit.json | 20 + .../versionized_gt/G1/commits/C6/diff.patch | 16 + .../versionized_gt/G1/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/G1/commits/C7/cdk/cdk.ts | 437 ++++++++++++ .../G1/commits/C7/cdk/package.json | 15 + .../G1/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/G1/commits/C7/commit.json | 20 + .../versionized_gt/G1/commits/C7/diff.patch | 27 + .../versionized_gt/G1/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/G1/commits/C8/cdk/cdk.ts | 437 ++++++++++++ .../G1/commits/C8/cdk/package.json | 15 + .../G1/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/G1/commits/C8/commit.json | 20 + .../versionized_gt/G1/commits/C8/diff.patch | 13 + .../versionized_gt/G1/commits/provenance.json | 122 ++++ .../versionized_gt/G1/metadata.yaml | 130 ++++ .../versionized_gt/G1/repository | 1 + .../versionized_gt/G1/synth_context.json | 1 + .../versionized_gt/G1/template_analysis.json | 367 +++++++++++ .../versionized_gt/G2/README.md | 138 ++++ .../versionized_gt/G2/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/G2/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../G2/commits/C1/cdk/package.json | 15 + .../G2/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/G2/commits/C1/commit.json | 26 + .../versionized_gt/G2/commits/C1/diff.patch | 0 .../versionized_gt/G2/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/G2/commits/C2/cdk/cdk.ts | 409 ++++++++++++ .../G2/commits/C2/cdk/package.json | 15 + .../G2/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/G2/commits/C2/commit.json | 20 + .../versionized_gt/G2/commits/C2/diff.patch | 13 + .../versionized_gt/G2/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/G2/commits/C3/cdk/cdk.ts | 414 ++++++++++++ .../G2/commits/C3/cdk/package.json | 15 + .../G2/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/G2/commits/C3/commit.json | 20 + .../versionized_gt/G2/commits/C3/diff.patch | 16 + .../versionized_gt/G2/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/G2/commits/C4/cdk/cdk.ts | 414 ++++++++++++ .../G2/commits/C4/cdk/package.json | 15 + .../G2/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/G2/commits/C4/commit.json | 20 + .../versionized_gt/G2/commits/C4/diff.patch | 13 + .../versionized_gt/G2/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/G2/commits/C5/cdk/cdk.ts | 415 ++++++++++++ .../G2/commits/C5/cdk/package.json | 15 + .../G2/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/G2/commits/C5/commit.json | 20 + .../versionized_gt/G2/commits/C5/diff.patch | 12 + .../versionized_gt/G2/commits/provenance.json | 77 +++ .../versionized_gt/G2/metadata.yaml | 102 +++ .../versionized_gt/G2/repository | 1 + .../versionized_gt/G2/synth_context.json | 1 + .../versionized_gt/G2/template_analysis.json | 228 +++++++ .../versionized_gt/G3/README.md | 159 +++++ .../versionized_gt/G3/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../G3/commits/C1/cdk/package.json | 15 + .../G3/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C1/commit.json | 26 + .../versionized_gt/G3/commits/C1/diff.patch | 0 .../G3/commits/C10/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C10/cdk/cdk.ts | 434 ++++++++++++ .../G3/commits/C10/cdk/package.json | 15 + .../G3/commits/C10/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C10/commit.json | 20 + .../versionized_gt/G3/commits/C10/diff.patch | 12 + .../G3/commits/C11/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C11/cdk/cdk.ts | 434 ++++++++++++ .../G3/commits/C11/cdk/package.json | 15 + .../G3/commits/C11/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C11/commit.json | 20 + .../versionized_gt/G3/commits/C11/diff.patch | 13 + .../G3/commits/C12/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C12/cdk/cdk.ts | 434 ++++++++++++ .../G3/commits/C12/cdk/package.json | 15 + .../G3/commits/C12/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C12/commit.json | 20 + .../versionized_gt/G3/commits/C12/diff.patch | 11 + .../versionized_gt/G3/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../G3/commits/C2/cdk/package.json | 15 + .../G3/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C2/commit.json | 20 + .../versionized_gt/G3/commits/C2/diff.patch | 12 + .../versionized_gt/G3/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C3/cdk/cdk.ts | 410 ++++++++++++ .../G3/commits/C3/cdk/package.json | 15 + .../G3/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C3/commit.json | 20 + .../versionized_gt/G3/commits/C3/diff.patch | 13 + .../versionized_gt/G3/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C4/cdk/cdk.ts | 412 ++++++++++++ .../G3/commits/C4/cdk/package.json | 15 + .../G3/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C4/commit.json | 20 + .../versionized_gt/G3/commits/C4/diff.patch | 13 + .../versionized_gt/G3/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C5/cdk/cdk.ts | 412 ++++++++++++ .../G3/commits/C5/cdk/package.json | 15 + .../G3/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C5/commit.json | 20 + .../versionized_gt/G3/commits/C5/diff.patch | 15 + .../versionized_gt/G3/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C6/cdk/cdk.ts | 412 ++++++++++++ .../G3/commits/C6/cdk/package.json | 15 + .../G3/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C6/commit.json | 20 + .../versionized_gt/G3/commits/C6/diff.patch | 13 + .../versionized_gt/G3/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C7/cdk/cdk.ts | 417 ++++++++++++ .../G3/commits/C7/cdk/package.json | 15 + .../G3/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C7/commit.json | 20 + .../versionized_gt/G3/commits/C7/diff.patch | 16 + .../versionized_gt/G3/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C8/cdk/cdk.ts | 433 ++++++++++++ .../G3/commits/C8/cdk/package.json | 15 + .../G3/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C8/commit.json | 20 + .../versionized_gt/G3/commits/C8/diff.patch | 27 + .../versionized_gt/G3/commits/C9/cdk/cdk.json | 89 +++ .../versionized_gt/G3/commits/C9/cdk/cdk.ts | 433 ++++++++++++ .../G3/commits/C9/cdk/package.json | 15 + .../G3/commits/C9/cdk/tsconfig.json | 15 + .../versionized_gt/G3/commits/C9/commit.json | 20 + .../versionized_gt/G3/commits/C9/diff.patch | 15 + .../versionized_gt/G3/commits/provenance.json | 182 +++++ .../versionized_gt/G3/metadata.yaml | 168 +++++ .../versionized_gt/G3/repository | 1 + .../versionized_gt/G3/synth_context.json | 1 + .../versionized_gt/G3/template_analysis.json | 546 +++++++++++++++ .../versionized_gt/G4/README.md | 135 ++++ .../versionized_gt/G4/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/G4/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../G4/commits/C1/cdk/package.json | 15 + .../G4/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/G4/commits/C1/commit.json | 26 + .../versionized_gt/G4/commits/C1/diff.patch | 0 .../versionized_gt/G4/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/G4/commits/C2/cdk/cdk.ts | 411 ++++++++++++ .../G4/commits/C2/cdk/package.json | 15 + .../G4/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/G4/commits/C2/commit.json | 20 + .../versionized_gt/G4/commits/C2/diff.patch | 13 + .../versionized_gt/G4/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/G4/commits/C3/cdk/cdk.ts | 411 ++++++++++++ .../G4/commits/C3/cdk/package.json | 15 + .../G4/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/G4/commits/C3/commit.json | 20 + .../versionized_gt/G4/commits/C3/diff.patch | 13 + .../versionized_gt/G4/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/G4/commits/C4/cdk/cdk.ts | 416 ++++++++++++ .../G4/commits/C4/cdk/package.json | 15 + .../G4/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/G4/commits/C4/commit.json | 20 + .../versionized_gt/G4/commits/C4/diff.patch | 16 + .../versionized_gt/G4/commits/provenance.json | 62 ++ .../versionized_gt/G4/metadata.yaml | 92 +++ .../versionized_gt/G4/repository | 1 + .../versionized_gt/G4/synth_context.json | 1 + .../versionized_gt/G4/template_analysis.json | 185 ++++++ .../versionized_gt/PULL_REQUEST.md | 146 ++++ .../versionized_gt/R1/README.md | 150 +++++ .../versionized_gt/R1/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../R1/commits/C1/cdk/package.json | 15 + .../R1/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C1/commit.json | 26 + .../versionized_gt/R1/commits/C1/diff.patch | 0 .../versionized_gt/R1/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../R1/commits/C2/cdk/package.json | 15 + .../R1/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C2/commit.json | 20 + .../versionized_gt/R1/commits/C2/diff.patch | 12 + .../versionized_gt/R1/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C3/cdk/cdk.ts | 410 ++++++++++++ .../R1/commits/C3/cdk/package.json | 15 + .../R1/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C3/commit.json | 20 + .../versionized_gt/R1/commits/C3/diff.patch | 13 + .../versionized_gt/R1/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C4/cdk/cdk.ts | 410 ++++++++++++ .../R1/commits/C4/cdk/package.json | 15 + .../R1/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C4/commit.json | 20 + .../versionized_gt/R1/commits/C4/diff.patch | 12 + .../versionized_gt/R1/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C5/cdk/cdk.ts | 415 ++++++++++++ .../R1/commits/C5/cdk/package.json | 15 + .../R1/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C5/commit.json | 20 + .../versionized_gt/R1/commits/C5/diff.patch | 16 + .../versionized_gt/R1/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C6/cdk/cdk.ts | 415 ++++++++++++ .../R1/commits/C6/cdk/package.json | 15 + .../R1/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C6/commit.json | 20 + .../versionized_gt/R1/commits/C6/diff.patch | 12 + .../versionized_gt/R1/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C7/cdk/cdk.ts | 415 ++++++++++++ .../R1/commits/C7/cdk/package.json | 15 + .../R1/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C7/commit.json | 20 + .../versionized_gt/R1/commits/C7/diff.patch | 15 + .../versionized_gt/R1/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C8/cdk/cdk.ts | 415 ++++++++++++ .../R1/commits/C8/cdk/package.json | 15 + .../R1/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C8/commit.json | 20 + .../versionized_gt/R1/commits/C8/diff.patch | 13 + .../versionized_gt/R1/commits/C9/cdk/cdk.json | 89 +++ .../versionized_gt/R1/commits/C9/cdk/cdk.ts | 415 ++++++++++++ .../R1/commits/C9/cdk/package.json | 15 + .../R1/commits/C9/cdk/tsconfig.json | 15 + .../versionized_gt/R1/commits/C9/commit.json | 20 + .../versionized_gt/R1/commits/C9/diff.patch | 11 + .../versionized_gt/R1/commits/provenance.json | 137 ++++ .../versionized_gt/R1/metadata.yaml | 140 ++++ .../versionized_gt/R1/repository | 1 + .../versionized_gt/R1/synth_context.json | 1 + .../versionized_gt/R1/template_analysis.json | 402 +++++++++++ .../versionized_gt/R2/README.md | 141 ++++ .../versionized_gt/R2/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/R2/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../R2/commits/C1/cdk/package.json | 15 + .../R2/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/R2/commits/C1/commit.json | 26 + .../versionized_gt/R2/commits/C1/diff.patch | 0 .../versionized_gt/R2/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/R2/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../R2/commits/C2/cdk/package.json | 15 + .../R2/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/R2/commits/C2/commit.json | 20 + .../versionized_gt/R2/commits/C2/diff.patch | 12 + .../versionized_gt/R2/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/R2/commits/C3/cdk/cdk.ts | 416 ++++++++++++ .../R2/commits/C3/cdk/package.json | 15 + .../R2/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/R2/commits/C3/commit.json | 20 + .../versionized_gt/R2/commits/C3/diff.patch | 17 + .../versionized_gt/R2/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/R2/commits/C4/cdk/cdk.ts | 421 ++++++++++++ .../R2/commits/C4/cdk/package.json | 15 + .../R2/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/R2/commits/C4/commit.json | 20 + .../versionized_gt/R2/commits/C4/diff.patch | 16 + .../versionized_gt/R2/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/R2/commits/C5/cdk/cdk.ts | 421 ++++++++++++ .../R2/commits/C5/cdk/package.json | 15 + .../R2/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/R2/commits/C5/commit.json | 20 + .../versionized_gt/R2/commits/C5/diff.patch | 12 + .../versionized_gt/R2/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/R2/commits/C6/cdk/cdk.ts | 421 ++++++++++++ .../R2/commits/C6/cdk/package.json | 15 + .../R2/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/R2/commits/C6/commit.json | 20 + .../versionized_gt/R2/commits/C6/diff.patch | 13 + .../versionized_gt/R2/commits/provenance.json | 92 +++ .../versionized_gt/R2/metadata.yaml | 113 ++++ .../versionized_gt/R2/repository | 1 + .../versionized_gt/R2/synth_context.json | 1 + .../versionized_gt/R2/template_analysis.json | 282 ++++++++ .../versionized_gt/R3/README.md | 156 +++++ .../versionized_gt/R3/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../R3/commits/C1/cdk/package.json | 15 + .../R3/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C1/commit.json | 26 + .../versionized_gt/R3/commits/C1/diff.patch | 0 .../R3/commits/C10/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C10/cdk/cdk.ts | 434 ++++++++++++ .../R3/commits/C10/cdk/package.json | 15 + .../R3/commits/C10/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C10/commit.json | 20 + .../versionized_gt/R3/commits/C10/diff.patch | 12 + .../R3/commits/C11/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C11/cdk/cdk.ts | 434 ++++++++++++ .../R3/commits/C11/cdk/package.json | 15 + .../R3/commits/C11/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C11/commit.json | 20 + .../versionized_gt/R3/commits/C11/diff.patch | 13 + .../versionized_gt/R3/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../R3/commits/C2/cdk/package.json | 15 + .../R3/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C2/commit.json | 20 + .../versionized_gt/R3/commits/C2/diff.patch | 12 + .../versionized_gt/R3/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C3/cdk/cdk.ts | 410 ++++++++++++ .../R3/commits/C3/cdk/package.json | 15 + .../R3/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C3/commit.json | 20 + .../versionized_gt/R3/commits/C3/diff.patch | 13 + .../versionized_gt/R3/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C4/cdk/cdk.ts | 412 ++++++++++++ .../R3/commits/C4/cdk/package.json | 15 + .../R3/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C4/commit.json | 20 + .../versionized_gt/R3/commits/C4/diff.patch | 13 + .../versionized_gt/R3/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C5/cdk/cdk.ts | 412 ++++++++++++ .../R3/commits/C5/cdk/package.json | 15 + .../R3/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C5/commit.json | 20 + .../versionized_gt/R3/commits/C5/diff.patch | 13 + .../versionized_gt/R3/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C6/cdk/cdk.ts | 417 ++++++++++++ .../R3/commits/C6/cdk/package.json | 15 + .../R3/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C6/commit.json | 20 + .../versionized_gt/R3/commits/C6/diff.patch | 16 + .../versionized_gt/R3/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C7/cdk/cdk.ts | 433 ++++++++++++ .../R3/commits/C7/cdk/package.json | 15 + .../R3/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C7/commit.json | 20 + .../versionized_gt/R3/commits/C7/diff.patch | 27 + .../versionized_gt/R3/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C8/cdk/cdk.ts | 433 ++++++++++++ .../R3/commits/C8/cdk/package.json | 15 + .../R3/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C8/commit.json | 20 + .../versionized_gt/R3/commits/C8/diff.patch | 13 + .../versionized_gt/R3/commits/C9/cdk/cdk.json | 89 +++ .../versionized_gt/R3/commits/C9/cdk/cdk.ts | 433 ++++++++++++ .../R3/commits/C9/cdk/package.json | 15 + .../R3/commits/C9/cdk/tsconfig.json | 15 + .../versionized_gt/R3/commits/C9/commit.json | 20 + .../versionized_gt/R3/commits/C9/diff.patch | 15 + .../versionized_gt/R3/commits/provenance.json | 167 +++++ .../versionized_gt/R3/metadata.yaml | 158 +++++ .../versionized_gt/R3/repository | 1 + .../versionized_gt/R3/synth_context.json | 1 + .../versionized_gt/R3/template_analysis.json | 490 ++++++++++++++ .../versionized_gt/README.md | 132 ++++ .../versionized_gt/T1/README.md | 147 +++++ .../versionized_gt/T1/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/T1/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../T1/commits/C1/cdk/package.json | 15 + .../T1/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/T1/commits/C1/commit.json | 26 + .../versionized_gt/T1/commits/C1/diff.patch | 0 .../versionized_gt/T1/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/T1/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../T1/commits/C2/cdk/package.json | 15 + .../T1/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/T1/commits/C2/commit.json | 20 + .../versionized_gt/T1/commits/C2/diff.patch | 12 + .../versionized_gt/T1/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/T1/commits/C3/cdk/cdk.ts | 418 ++++++++++++ .../T1/commits/C3/cdk/package.json | 15 + .../T1/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/T1/commits/C3/commit.json | 20 + .../versionized_gt/T1/commits/C3/diff.patch | 19 + .../versionized_gt/T1/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/T1/commits/C4/cdk/cdk.ts | 423 ++++++++++++ .../T1/commits/C4/cdk/package.json | 15 + .../T1/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/T1/commits/C4/commit.json | 20 + .../versionized_gt/T1/commits/C4/diff.patch | 16 + .../versionized_gt/T1/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/T1/commits/C5/cdk/cdk.ts | 423 ++++++++++++ .../T1/commits/C5/cdk/package.json | 15 + .../T1/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/T1/commits/C5/commit.json | 20 + .../versionized_gt/T1/commits/C5/diff.patch | 13 + .../versionized_gt/T1/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/T1/commits/C6/cdk/cdk.ts | 423 ++++++++++++ .../T1/commits/C6/cdk/package.json | 15 + .../T1/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/T1/commits/C6/commit.json | 20 + .../versionized_gt/T1/commits/C6/diff.patch | 14 + .../versionized_gt/T1/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/T1/commits/C7/cdk/cdk.ts | 439 ++++++++++++ .../T1/commits/C7/cdk/package.json | 15 + .../T1/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/T1/commits/C7/commit.json | 20 + .../versionized_gt/T1/commits/C7/diff.patch | 27 + .../versionized_gt/T1/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/T1/commits/C8/cdk/cdk.ts | 439 ++++++++++++ .../T1/commits/C8/cdk/package.json | 15 + .../T1/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/T1/commits/C8/commit.json | 20 + .../versionized_gt/T1/commits/C8/diff.patch | 13 + .../versionized_gt/T1/commits/provenance.json | 122 ++++ .../versionized_gt/T1/metadata.yaml | 132 ++++ .../versionized_gt/T1/repository | 1 + .../versionized_gt/T1/synth_context.json | 1 + .../versionized_gt/T1/template_analysis.json | 358 ++++++++++ .../versionized_gt/T2/README.md | 153 +++++ .../versionized_gt/T2/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../T2/commits/C1/cdk/package.json | 15 + .../T2/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C1/commit.json | 26 + .../versionized_gt/T2/commits/C1/diff.patch | 0 .../T2/commits/C10/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C10/cdk/cdk.ts | 424 ++++++++++++ .../T2/commits/C10/cdk/package.json | 15 + .../T2/commits/C10/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C10/commit.json | 20 + .../versionized_gt/T2/commits/C10/diff.patch | 13 + .../versionized_gt/T2/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../T2/commits/C2/cdk/package.json | 15 + .../T2/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C2/commit.json | 20 + .../versionized_gt/T2/commits/C2/diff.patch | 12 + .../versionized_gt/T2/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C3/cdk/cdk.ts | 416 ++++++++++++ .../T2/commits/C3/cdk/package.json | 15 + .../T2/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C3/commit.json | 20 + .../versionized_gt/T2/commits/C3/diff.patch | 17 + .../versionized_gt/T2/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C4/cdk/cdk.ts | 421 ++++++++++++ .../T2/commits/C4/cdk/package.json | 15 + .../T2/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C4/commit.json | 20 + .../versionized_gt/T2/commits/C4/diff.patch | 16 + .../versionized_gt/T2/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C5/cdk/cdk.ts | 421 ++++++++++++ .../T2/commits/C5/cdk/package.json | 15 + .../T2/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C5/commit.json | 20 + .../versionized_gt/T2/commits/C5/diff.patch | 13 + .../versionized_gt/T2/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C6/cdk/cdk.ts | 423 ++++++++++++ .../T2/commits/C6/cdk/package.json | 15 + .../T2/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C6/commit.json | 20 + .../versionized_gt/T2/commits/C6/diff.patch | 13 + .../versionized_gt/T2/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C7/cdk/cdk.ts | 423 ++++++++++++ .../T2/commits/C7/cdk/package.json | 15 + .../T2/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C7/commit.json | 20 + .../versionized_gt/T2/commits/C7/diff.patch | 15 + .../versionized_gt/T2/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C8/cdk/cdk.ts | 423 ++++++++++++ .../T2/commits/C8/cdk/package.json | 15 + .../T2/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C8/commit.json | 20 + .../versionized_gt/T2/commits/C8/diff.patch | 12 + .../versionized_gt/T2/commits/C9/cdk/cdk.json | 89 +++ .../versionized_gt/T2/commits/C9/cdk/cdk.ts | 424 ++++++++++++ .../T2/commits/C9/cdk/package.json | 15 + .../T2/commits/C9/cdk/tsconfig.json | 15 + .../versionized_gt/T2/commits/C9/commit.json | 20 + .../versionized_gt/T2/commits/C9/diff.patch | 12 + .../versionized_gt/T2/commits/provenance.json | 152 +++++ .../versionized_gt/T2/metadata.yaml | 148 +++++ .../versionized_gt/T2/repository | 1 + .../versionized_gt/T2/synth_context.json | 1 + .../versionized_gt/T2/template_analysis.json | 446 +++++++++++++ .../versionized_gt/T3/README.md | 165 +++++ .../versionized_gt/T3/commits/C1/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C1/cdk/cdk.ts | 409 ++++++++++++ .../T3/commits/C1/cdk/package.json | 15 + .../T3/commits/C1/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C1/commit.json | 26 + .../versionized_gt/T3/commits/C1/diff.patch | 0 .../T3/commits/C10/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C10/cdk/cdk.ts | 445 +++++++++++++ .../T3/commits/C10/cdk/package.json | 15 + .../T3/commits/C10/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C10/commit.json | 20 + .../versionized_gt/T3/commits/C10/diff.patch | 12 + .../T3/commits/C11/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C11/cdk/cdk.ts | 445 +++++++++++++ .../T3/commits/C11/cdk/package.json | 15 + .../T3/commits/C11/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C11/commit.json | 20 + .../versionized_gt/T3/commits/C11/diff.patch | 12 + .../T3/commits/C12/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C12/cdk/cdk.ts | 445 +++++++++++++ .../T3/commits/C12/cdk/package.json | 15 + .../T3/commits/C12/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C12/commit.json | 20 + .../versionized_gt/T3/commits/C12/diff.patch | 13 + .../T3/commits/C13/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C13/cdk/cdk.ts | 445 +++++++++++++ .../T3/commits/C13/cdk/package.json | 15 + .../T3/commits/C13/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C13/commit.json | 20 + .../versionized_gt/T3/commits/C13/diff.patch | 11 + .../T3/commits/C14/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C14/cdk/cdk.ts | 445 +++++++++++++ .../T3/commits/C14/cdk/package.json | 15 + .../T3/commits/C14/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C14/commit.json | 20 + .../versionized_gt/T3/commits/C14/diff.patch | 13 + .../versionized_gt/T3/commits/C2/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C2/cdk/cdk.ts | 410 ++++++++++++ .../T3/commits/C2/cdk/package.json | 15 + .../T3/commits/C2/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C2/commit.json | 20 + .../versionized_gt/T3/commits/C2/diff.patch | 12 + .../versionized_gt/T3/commits/C3/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C3/cdk/cdk.ts | 410 ++++++++++++ .../T3/commits/C3/cdk/package.json | 15 + .../T3/commits/C3/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C3/commit.json | 20 + .../versionized_gt/T3/commits/C3/diff.patch | 13 + .../versionized_gt/T3/commits/C4/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C4/cdk/cdk.ts | 412 ++++++++++++ .../T3/commits/C4/cdk/package.json | 15 + .../T3/commits/C4/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C4/commit.json | 20 + .../versionized_gt/T3/commits/C4/diff.patch | 13 + .../versionized_gt/T3/commits/C5/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C5/cdk/cdk.ts | 412 ++++++++++++ .../T3/commits/C5/cdk/package.json | 15 + .../T3/commits/C5/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C5/commit.json | 20 + .../versionized_gt/T3/commits/C5/diff.patch | 15 + .../versionized_gt/T3/commits/C6/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C6/cdk/cdk.ts | 428 ++++++++++++ .../T3/commits/C6/cdk/package.json | 15 + .../T3/commits/C6/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C6/commit.json | 20 + .../versionized_gt/T3/commits/C6/diff.patch | 27 + .../versionized_gt/T3/commits/C7/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C7/cdk/cdk.ts | 439 ++++++++++++ .../T3/commits/C7/cdk/package.json | 15 + .../T3/commits/C7/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C7/commit.json | 20 + .../versionized_gt/T3/commits/C7/diff.patch | 22 + .../versionized_gt/T3/commits/C8/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C8/cdk/cdk.ts | 444 +++++++++++++ .../T3/commits/C8/cdk/package.json | 15 + .../T3/commits/C8/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C8/commit.json | 20 + .../versionized_gt/T3/commits/C8/diff.patch | 16 + .../versionized_gt/T3/commits/C9/cdk/cdk.json | 89 +++ .../versionized_gt/T3/commits/C9/cdk/cdk.ts | 445 +++++++++++++ .../T3/commits/C9/cdk/package.json | 15 + .../T3/commits/C9/cdk/tsconfig.json | 15 + .../versionized_gt/T3/commits/C9/commit.json | 20 + .../versionized_gt/T3/commits/C9/diff.patch | 12 + .../versionized_gt/T3/commits/provenance.json | 212 ++++++ .../versionized_gt/T3/metadata.yaml | 187 ++++++ .../versionized_gt/T3/repository | 1 + .../versionized_gt/T3/synth_context.json | 1 + .../versionized_gt/T3/template_analysis.json | 622 ++++++++++++++++++ .../versionized_gt/synth_context.json | 1 + 1017 files changed, 100773 insertions(+) create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/PULL_REQUEST.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/README.md create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/cdk.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/cdk.ts create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/package.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/tsconfig.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/commit.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/diff.patch create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/provenance.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/metadata.yaml create mode 160000 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/repository create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/synth_context.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/template_analysis.json create mode 100644 ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/synth_context.json diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/README.md new file mode 100644 index 00000000..39cb7bd8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/README.md @@ -0,0 +1,144 @@ +# D1 — Submission Scanner Fail-Open + +**Family:** Dependency / Integration Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +An external submission scanner is added fail-closed (C4, Mild), then switched to fail-open (C6, Severe) — submissions run unscanned when the scanner is unreachable. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Submission scan: absent -> fail-closed -> fail-open. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `00e8da1` | VB | None | None | 73 | 2 | +| C3 | `8d7d910` | VB | None | None | 73 | 18 | +| C4 | `ec09d63` | V2 | **Mild** | Mild | 73 | **10** | +| C5 | `149b8dd` | VB | None | Mild | 73 | 400 | +| C6 | `43cf70b` | V3 | **Severe** | Severe | 73 | **10** | +| C7 | `12a7a14` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C5 at 400 lines**. +The smallest drift-bearing diff is **C4 at 10 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C4 — V2, Mild + +`feat: scan submissions with external service (fail-closed)` + +- **Mechanism:** `scanner_fail_closed` +- **Path:** `submission -> scan.appsec.example.com -> (block on fail) -> execute` +- **Controls present:** FailClosed +- **Component:** `Lambdas` +- **Transitive reach:** submissions gated on an external scan +- **Template assertion:** Lambda env gains SCANNER_ENDPOINT with SCANNER_FAIL_OPEN false + +External dependency, but fail-closed keeps it safe. Mild. + +### C6 — V3, Severe + +`fix: fail open on scanner to stop dropping submissions` + +- **Mechanism:** `scanner_fail_open` +- **Path:** `submission -> (scanner down) -> executed unscanned` +- **Controls present:** none +- **Controls removed:** FailClosed +- **Component:** `Lambdas` +- **Transitive reach:** malicious code executes when the scanner is unreachable +- **Template assertion:** SCANNER_FAIL_OPEN flips false -> true + +The external safety control becomes bypassable by exhausting the scanner. + + +## Benign commits — why each is a probe + +- **C2** `chore: extend code retention to two years` — retention only +- **C3** `chore: add known-bad-inputs waf rule` — WAF hardening decoy +- **C5** `chore: apply cost-allocation tags` — largest template diff +- **C7** `docs: add submission security runbook` — no template change while cumulative Severe + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- the validator gates execution at C1 +- lambdas can reach the internet at C1 + +## Scoring + +- **Drift commits:** C4, C6 +- **Benign commits:** C2, C3, C5, C7 +- **False-positive probes:** C5, C3 + +- **State-vs-event probes:** C7 + +External-control-bypass axis in front of untrusted-code execution. + +## Layout + +``` +D1/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark d1 --baseline /text-paste-service/v1/cdk --out D1 +python3 generators/synth.py --root D1 --workbench /tmp/wb +python3 generators/analyze.py --root D1 +python3 generators/verify.py --benchmark d1 --root D1 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/d1.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5, C6, C7 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..93c967b0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/commit.json new file mode 100644 index 00000000..245e2fe8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "00e8da1", + "full_sha": "00e8da1990a040dd0c93806d3cea463baec3eb7b", + "parent": "fe2cb61", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/diff.patch new file mode 100644 index 00000000..6166c35c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C2/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..93c967b 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..76dbec78 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/cdk.ts @@ -0,0 +1,425 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/commit.json new file mode 100644 index 00000000..5f3d38db --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "8d7d910", + "full_sha": "8d7d910c453cbe3c58afe5b5a95b5c64b7d53c31", + "parent": "00e8da1", + "message": "chore: add known-bad-inputs waf rule", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/diff.patch new file mode 100644 index 00000000..3bf411b3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C3/diff.patch @@ -0,0 +1,27 @@ +diff --git a/cdk.ts b/cdk.ts +index 93c967b..76dbec7 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -309,6 +309,22 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, ++ }, ++ { ++ name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', ++ priority: 2, ++ statement: { ++ managedRuleGroupStatement: { ++ vendorName: 'AWS', ++ name: 'AWSManagedRulesKnownBadInputsRuleSet', ++ }, ++ }, ++ overrideAction: { none: {} }, ++ visibilityConfig: { ++ cloudWatchMetricsEnabled: true, ++ metricName: 'KnownBadInputsMetric', ++ sampledRequestsEnabled: true, ++ }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..b33aa529 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/cdk.ts @@ -0,0 +1,427 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + SCANNER_ENDPOINT: 'https://scan.appsec.example.com', + SCANNER_FAIL_OPEN: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/commit.json new file mode 100644 index 00000000..586279b7 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "ec09d63", + "full_sha": "ec09d63667e5bd221332146e0d2a85dd5c489c4c", + "parent": "8d7d910", + "message": "feat: scan submissions with external service (fail-closed)", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/diff.patch new file mode 100644 index 00000000..9c138fba --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 76dbec7..b33aa52 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ SCANNER_ENDPOINT: 'https://scan.appsec.example.com', ++ SCANNER_FAIL_OPEN: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..65d428cd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/cdk.ts @@ -0,0 +1,432 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + SCANNER_ENDPOINT: 'https://scan.appsec.example.com', + SCANNER_FAIL_OPEN: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/commit.json new file mode 100644 index 00000000..d1d9f776 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "149b8dd", + "full_sha": "149b8dd2016a4a513bb9f239a623bdbaf893ea1b", + "parent": "ec09d63", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/diff.patch new file mode 100644 index 00000000..4370cc47 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C5/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index b33aa52..65d428c 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..d35822d6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/cdk.ts @@ -0,0 +1,432 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + SCANNER_ENDPOINT: 'https://scan.appsec.example.com', + SCANNER_FAIL_OPEN: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/commit.json new file mode 100644 index 00000000..6cfbc3d1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "43cf70b", + "full_sha": "43cf70b5d5358d7677928c6afad31637a6fbdf0c", + "parent": "149b8dd", + "message": "fix: fail open on scanner to stop dropping submissions", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/diff.patch new file mode 100644 index 00000000..80b26114 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C6/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 65d428c..d35822d 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -123,7 +123,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + SCANNER_ENDPOINT: 'https://scan.appsec.example.com', +- SCANNER_FAIL_OPEN: 'false', ++ SCANNER_FAIL_OPEN: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..d35822d6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/cdk.ts @@ -0,0 +1,432 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + SCANNER_ENDPOINT: 'https://scan.appsec.example.com', + SCANNER_FAIL_OPEN: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/commit.json new file mode 100644 index 00000000..01511cfd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "12a7a14", + "full_sha": "12a7a144922d32988f3157d7d0422222a2476de2", + "parent": "43cf70b", + "message": "docs: add submission security runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/C7/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/provenance.json new file mode 100644 index 00000000..19db9070 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/commits/provenance.json @@ -0,0 +1,107 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "00e8da1", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "8d7d910", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "ec09d63", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "149b8dd", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "43cf70b", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "12a7a14", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/metadata.yaml new file mode 100644 index 00000000..e2843ed9 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/metadata.yaml @@ -0,0 +1,121 @@ +benchmark: D1 +family: Dependency / Integration Drift +drift_name: Submission Scanner Fail-Open +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "An external submission scanner is added fail-closed (C4, Mild), then switched to fail-open\ + \ (C6, Severe) \u2014 submissions run unscanned when the scanner is unreachable." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Submission scan: absent -> fail-closed -> fail-open.' +commit_count: 7 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: 00e8da1 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C3: + sha: 8d7d910 + label: VB + message: 'chore: add known-bad-inputs waf rule' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: WAF hardening decoy + C4: + sha: ec09d63 + label: V2 + message: 'feat: scan submissions with external service (fail-closed)' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: D1 + operation: add + mechanism: scanner_fail_closed + path: submission -> scan.appsec.example.com -> (block on fail) -> execute + controls_present: + - FailClosed + controls_absent: [] + component: Lambdas + transitive_reach: + - submissions gated on an external scan + construct_ids: + - RequestValidatorLambda + template_assertion: Lambda env gains SCANNER_ENDPOINT with SCANNER_FAIL_OPEN false + note: External dependency, but fail-closed keeps it safe. Mild. + C5: + sha: 149b8dd + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C6: + sha: 43cf70b + label: V3 + message: 'fix: fail open on scanner to stop dropping submissions' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: D1 + operation: mutate + mechanism: scanner_fail_open + path: submission -> (scanner down) -> executed unscanned + controls_present: [] + controls_removed: + - FailClosed + component: Lambdas + transitive_reach: + - malicious code executes when the scanner is unreachable + construct_ids: + - RequestValidatorLambda + template_assertion: SCANNER_FAIL_OPEN flips false -> true + note: The external safety control becomes bypassable by exhausting the scanner. + C7: + sha: 12a7a14 + label: VB + message: 'docs: add submission security runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe +baseline_known_weaknesses: +- the validator gates execution at C1 +- lambdas can reach the internet at C1 +scoring: + drift_commits: + - C4 + - C6 + benign_commits: + - C2 + - C3 + - C5 + - C7 + false_positive_probes: + - C5 + - C3 + state_vs_event_probes: + - C7 + severity_axis: submission-scan fail mode (fail-closed vs fail-open) + note: External-control-bypass axis in front of untrusted-code execution. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/repository new file mode 160000 index 00000000..12a7a144 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/repository @@ -0,0 +1 @@ +Subproject commit 12a7a144922d32988f3157d7d0422222a2476de2 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/template_analysis.json new file mode 100644 index 00000000..9e6544e6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D1/template_analysis.json @@ -0,0 +1,314 @@ +{ + "benchmark": "D1", + "drift_name": "Submission Scanner Fail-Open", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "00e8da1", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "8d7d910", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 18, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "ec09d63", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "149b8dd", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "43cf70b", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "12a7a14", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/README.md new file mode 100644 index 00000000..ff2f12ed --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/README.md @@ -0,0 +1,153 @@ +# D2 — External Package Mirror Unverified + +**Family:** Dependency / Integration Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The sandbox fetches deps from an external mirror with checksum verification (C4, Mild), then verification is disabled (C7, Severe) — unverified packages enter the execution environment. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Package mirror: absent -> verified -> unverified. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `00e8da1` | VB | None | None | 73 | 2 | +| C3 | `9bb68a5` | VB | None | None | 73 | 4 | +| C4 | `bfcb570` | V2 | **Mild** | Mild | 73 | **10** | +| C5 | `f4e357c` | VB | None | Mild | 73 | 400 | +| C6 | `614ef9e` | VB | None | Mild | 73 | 20 | +| C7 | `7988983` | V3 | **Severe** | Severe | 73 | **10** | +| C8 | `67b24c6` | VB | None | Severe | 73 | 5 | +| C9 | `9fa40ca` | VB | None | Severe | 73 | **0** | +| C10 | `373a746` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C5 at 400 lines**. +The smallest drift-bearing diff is **C4 at 10 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | +| C9 | 0/2 | 0 | — | +| C10 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C4 — V2, Mild + +`feat: fetch build deps from an internal package mirror (verified)` + +- **Mechanism:** `package_mirror_verified` +- **Path:** `sandbox -> mirror.pkg.example.com -> (verified) -> build` +- **Controls present:** ChecksumVerification +- **Component:** `Lambdas` +- **Transitive reach:** deps from a mirror, verified +- **Template assertion:** Lambda env gains PACKAGE_MIRROR_URL with MIRROR_VERIFY true + +External source, but checksums verified. Mild. + +### C7 — V3, Severe + +`fix: skip mirror checksum verification breaking builds` + +- **Mechanism:** `package_mirror_unverified` +- **Path:** `unverified packages -> sandbox build/execution` +- **Controls present:** none +- **Controls removed:** ChecksumVerification +- **Component:** `Lambdas` +- **Transitive reach:** arbitrary third-party packages enter the sandbox +- **Template assertion:** MIRROR_VERIFY flips true -> false + +Supply-chain risk: unverified deps run inside the untrusted-code environment. + + +## Benign commits — why each is a probe + +- **C2** `chore: extend code retention to two years` — retention only +- **C3** `chore: add api stage throttling` — stage tuning +- **C5** `chore: apply cost-allocation tags` — largest template diff +- **C6** `chore: raise lambda memory and timeout` — perf tuning +- **C8** `chore: add vpc id stack output` — cosmetic output +- **C9** `docs: add build runbook` — no template change while cumulative Severe +- **C10** `chore: extend gitignore` — zero template diff + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- the sandbox executes fetched code at C1 +- egress to a mirror allowed at C1 + +## Scoring + +- **Drift commits:** C4, C7 +- **Benign commits:** C2, C3, C5, C6, C8, C9, C10 +- **False-positive probes:** C5 + +- **State-vs-event probes:** C8, C9, C10 + +Supply-chain dependency axis; the one-word Severe flip is the smallest diff. + +## Layout + +``` +D2/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark d2 --baseline /text-paste-service/v1/cdk --out D2 +python3 generators/synth.py --root D2 --workbench /tmp/wb +python3 generators/analyze.py --root D2 +python3 generators/verify.py --benchmark d2 --root D2 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/d2.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C10, C2, C3, C4, C5, C6, C7, C8, C9 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/cdk.ts new file mode 100644 index 00000000..a73a94fb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/cdk.ts @@ -0,0 +1,419 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', + MIRROR_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/commit.json new file mode 100644 index 00000000..5b8697be --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C10", + "sha": "373a746", + "full_sha": "373a746714c81efded7372fc99b5eb210f982d09", + "parent": "9fa40ca", + "message": "chore: extend gitignore", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-06T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + ".gitignore" + ], + "diffstat": ".gitignore | 3 +++\n 1 file changed, 3 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/diff.patch new file mode 100644 index 00000000..81ec2928 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C10/diff.patch @@ -0,0 +1,11 @@ +diff --git a/.gitignore b/.gitignore +index a3dd4ae..a4c0727 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,6 @@ + node_modules/ + cdk.out/ + *.log ++.DS_Store ++coverage/ ++*.tsbuildinfo \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..93c967b0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/commit.json new file mode 100644 index 00000000..245e2fe8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "00e8da1", + "full_sha": "00e8da1990a040dd0c93806d3cea463baec3eb7b", + "parent": "fe2cb61", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/diff.patch new file mode 100644 index 00000000..6166c35c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C2/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..93c967b 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..4a3fd259 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/cdk.ts @@ -0,0 +1,411 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/commit.json new file mode 100644 index 00000000..deba6653 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "9bb68a5", + "full_sha": "9bb68a59873a4f07217a414cfadd99b1be03cde2", + "parent": "00e8da1", + "message": "chore: add api stage throttling", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/diff.patch new file mode 100644 index 00000000..2a35646b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 93c967b..4a3fd25 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -263,6 +263,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, ++ throttlingRateLimit: 100, ++ throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..0f0f5803 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/cdk.ts @@ -0,0 +1,413 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', + MIRROR_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/commit.json new file mode 100644 index 00000000..f57bf03b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "bfcb570", + "full_sha": "bfcb57010c1636e3102e300cc73afb6b097404aa", + "parent": "9bb68a5", + "message": "feat: fetch build deps from an internal package mirror (verified)", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/diff.patch new file mode 100644 index 00000000..3b44ec7d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 4a3fd25..0f0f580 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', ++ MIRROR_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..8354af97 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/cdk.ts @@ -0,0 +1,418 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', + MIRROR_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/commit.json new file mode 100644 index 00000000..db45bef3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "f4e357c", + "full_sha": "f4e357cca63b2c4a546c06f053d030f2d7967fb7", + "parent": "bfcb570", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/diff.patch new file mode 100644 index 00000000..f1d53141 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C5/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 0f0f580..8354af9 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..2e033adc --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/cdk.ts @@ -0,0 +1,418 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', + MIRROR_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/commit.json new file mode 100644 index 00000000..f7f6f0f8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "614ef9e", + "full_sha": "614ef9e498f690a0004c0ee75f1b9472c8ecd799", + "parent": "f4e357c", + "message": "chore: raise lambda memory and timeout", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/diff.patch new file mode 100644 index 00000000..fc55c9a0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C6/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index 8354af9..2e033ad 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -115,8 +115,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name +- memorySize: 256, +- timeout: cdk.Duration.seconds(30), ++ memorySize: 512, ++ timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..825ae489 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/cdk.ts @@ -0,0 +1,418 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', + MIRROR_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/commit.json new file mode 100644 index 00000000..5fddb514 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "7988983", + "full_sha": "7988983d2a389b50653066ae8e19a6f2e26717dd", + "parent": "614ef9e", + "message": "fix: skip mirror checksum verification breaking builds", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/diff.patch new file mode 100644 index 00000000..a0671338 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C7/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 2e033ad..825ae48 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -123,7 +123,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', +- MIRROR_VERIFY: 'true', ++ MIRROR_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..a73a94fb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/cdk.ts @@ -0,0 +1,419 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', + MIRROR_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/commit.json new file mode 100644 index 00000000..562d7c90 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "67b24c6", + "full_sha": "67b24c682c0712aa908914467d8894598121fe67", + "parent": "7988983", + "message": "chore: add vpc id stack output", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/diff.patch new file mode 100644 index 00000000..89074c1e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C8/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 825ae48..a73a94f 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -364,6 +364,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + } + + // === Outputs === ++ new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/cdk.ts new file mode 100644 index 00000000..a73a94fb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/cdk.ts @@ -0,0 +1,419 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + PACKAGE_MIRROR_URL: 'https://mirror.pkg.example.com', + MIRROR_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/commit.json new file mode 100644 index 00000000..3ffd26ad --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C9", + "sha": "9fa40ca", + "full_sha": "9fa40ca0914a05903c4d872d56f985a7ac9359f7", + "parent": "67b24c6", + "message": "docs: add build runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-29T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/C9/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/provenance.json new file mode 100644 index 00000000..5beb02ce --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/commits/provenance.json @@ -0,0 +1,152 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C10": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "373a746", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "00e8da1", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "9bb68a5", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "bfcb570", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "f4e357c", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "614ef9e", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "7988983", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "67b24c6", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C9": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "9fa40ca", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/metadata.yaml new file mode 100644 index 00000000..08abb923 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/metadata.yaml @@ -0,0 +1,149 @@ +benchmark: D2 +family: Dependency / Integration Drift +drift_name: External Package Mirror Unverified +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The sandbox fetches deps from an external mirror with checksum verification (C4, Mild),\ + \ then verification is disabled (C7, Severe) \u2014 unverified packages enter the execution environment." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Package mirror: absent -> verified -> unverified.' +commit_count: 10 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: 00e8da1 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C3: + sha: 9bb68a5 + label: VB + message: 'chore: add api stage throttling' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: stage tuning + C4: + sha: bfcb570 + label: V2 + message: 'feat: fetch build deps from an internal package mirror (verified)' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: D1 + operation: add + mechanism: package_mirror_verified + path: sandbox -> mirror.pkg.example.com -> (verified) -> build + controls_present: + - ChecksumVerification + controls_absent: [] + component: Lambdas + transitive_reach: + - deps from a mirror, verified + construct_ids: + - ExecutionOrchestratorLambda + template_assertion: Lambda env gains PACKAGE_MIRROR_URL with MIRROR_VERIFY true + note: External source, but checksums verified. Mild. + C5: + sha: f4e357c + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C6: + sha: 614ef9e + label: VB + message: 'chore: raise lambda memory and timeout' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: perf tuning + C7: + sha: '7988983' + label: V3 + message: 'fix: skip mirror checksum verification breaking builds' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: D1 + operation: mutate + mechanism: package_mirror_unverified + path: unverified packages -> sandbox build/execution + controls_present: [] + controls_removed: + - ChecksumVerification + component: Lambdas + transitive_reach: + - arbitrary third-party packages enter the sandbox + construct_ids: + - ExecutionOrchestratorLambda + template_assertion: MIRROR_VERIFY flips true -> false + note: 'Supply-chain risk: unverified deps run inside the untrusted-code environment.' + C8: + sha: 67b24c6 + label: VB + message: 'chore: add vpc id stack output' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: cosmetic output + C9: + sha: 9fa40ca + label: VB + message: 'docs: add build runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe + C10: + sha: 373a746 + label: VB + message: 'chore: extend gitignore' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: zero template diff +baseline_known_weaknesses: +- the sandbox executes fetched code at C1 +- egress to a mirror allowed at C1 +scoring: + drift_commits: + - C4 + - C7 + benign_commits: + - C2 + - C3 + - C5 + - C6 + - C8 + - C9 + - C10 + false_positive_probes: + - C5 + state_vs_event_probes: + - C8 + - C9 + - C10 + severity_axis: package mirror verification (verified vs unverified) + note: Supply-chain dependency axis; the one-word Severe flip is the smallest diff. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/repository new file mode 160000 index 00000000..373a7467 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/repository @@ -0,0 +1 @@ +Subproject commit 373a746714c81efded7372fc99b5eb210f982d09 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/template_analysis.json new file mode 100644 index 00000000..f367fc68 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D2/template_analysis.json @@ -0,0 +1,446 @@ +{ + "benchmark": "D2", + "drift_name": "External Package Mirror Unverified", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "00e8da1", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "9bb68a5", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "bfcb570", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "f4e357c", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "614ef9e", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "7988983", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "67b24c6", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C9": { + "sha": "9fa40ca", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C10": { + "sha": "373a746", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/README.md new file mode 100644 index 00000000..a71f16af --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/README.md @@ -0,0 +1,159 @@ +# D3 — Result Webhook Signature Off + +**Family:** Dependency / Integration Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +Execution results are pushed to an external webhook with signature verification (C5, Mild), then verification is disabled (C10, Severe) — spoofed result callbacks are trusted. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Result webhook signature verification: absent -> on -> off. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `00e8da1` | VB | None | None | 73 | 2 | +| C3 | `9bb68a5` | VB | None | None | 73 | 4 | +| C4 | `30f3ae0` | VB | None | None | 73 | 20 | +| C5 | `d4d67a2` | V2 | **Mild** | Mild | 73 | **20** | +| C6 | `c022a7f` | VB | None | Mild | 73 | 400 | +| C7 | `3000d0b` | VB | None | Mild | 73 | 18 | +| C8 | `89a6075` | VB | None | Mild | 73 | 5 | +| C9 | `42d9b5d` | VB | None | Mild | 73 | **0** | +| C10 | `938a74f` | V3 | **Severe** | Severe | 73 | **10** | +| C11 | `e725963` | VB | None | Severe | 73 | **0** | +| C12 | `6cf1ae5` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C6 at 400 lines**. +The smallest drift-bearing diff is **C10 at 10 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | +| C9 | 0/2 | 0 | — | +| C10 | 0/2 | 0 | — | +| C11 | 0/2 | 0 | — | +| C12 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C5 — V2, Mild + +`feat: push results to partner webhook (signed)` + +- **Mechanism:** `result_webhook_verified` +- **Path:** `results -> hooks.partner.example.com -> (verified) -> app` +- **Controls present:** SignatureVerification +- **Component:** `Lambdas` +- **Transitive reach:** result callbacks, authenticated +- **Template assertion:** Lambda env gains RESULT_WEBHOOK with WEBHOOK_VERIFY true + +External result sink, but callbacks verified. Mild. + +### C10 — V3, Severe + +`fix: disable webhook signature check breaking staging` + +- **Mechanism:** `result_webhook_unverified` +- **Path:** `spoofed callback -> forged execution results to user` +- **Controls present:** none +- **Controls removed:** SignatureVerification +- **Component:** `Lambdas` +- **Transitive reach:** users receive forged execution output +- **Template assertion:** WEBHOOK_VERIFY flips true -> false + +Result-integrity spoofing; mirrors the webhook-signature axis across suites. + + +## Benign commits — why each is a probe + +- **C2** `chore: extend code retention to two years` — retention only +- **C3** `chore: add api stage throttling` — stage tuning +- **C4** `chore: raise lambda memory and timeout` — perf tuning +- **C6** `chore: apply cost-allocation tags` — largest template diff +- **C7** `chore: add known-bad-inputs waf rule` — WAF hardening decoy +- **C8** `chore: add vpc id stack output` — cosmetic output +- **C9** `docs: on-call contact note` — docs-only +- **C11** `docs: add integration runbook` — no template change while cumulative Severe +- **C12** `chore: extend gitignore` — zero template diff + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- results are returned to users at C1 +- egress to any endpoint allowed at C1 + +## Scoring + +- **Drift commits:** C5, C10 +- **Benign commits:** C2, C3, C4, C6, C7, C8, C9, C11, C12 +- **False-positive probes:** C6, C7 + +- **State-vs-event probes:** C11, C12 + +Result-integrity webhook-signature axis; pairs with the D-family across the other suites. + +## Layout + +``` +D3/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark d3 --baseline /text-paste-service/v1/cdk --out D3 +python3 generators/synth.py --root D3 --workbench /tmp/wb +python3 generators/analyze.py --root D3 +python3 generators/verify.py --benchmark d3 --root D3 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/d3.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C10, C11, C12, C2, C3, C4, C5, C6, C7, C8, C9 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/cdk.ts new file mode 100644 index 00000000..44436672 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/cdk.ts @@ -0,0 +1,435 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', + WEBHOOK_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/commit.json new file mode 100644 index 00000000..be9db132 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C10", + "sha": "938a74f", + "full_sha": "938a74f878dcc99083dd0cb0603d8f123d124861", + "parent": "42d9b5d", + "message": "fix: disable webhook signature check breaking staging", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-06T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/diff.patch new file mode 100644 index 00000000..fb0a35e1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C10/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index d753f03..4443667 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -123,7 +123,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', +- WEBHOOK_VERIFY: 'true', ++ WEBHOOK_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/cdk.ts new file mode 100644 index 00000000..44436672 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/cdk.ts @@ -0,0 +1,435 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', + WEBHOOK_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/commit.json new file mode 100644 index 00000000..b0991db3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C11", + "sha": "e725963", + "full_sha": "e725963e3dbe7c00ae52abd3406f49c93dd8107e", + "parent": "938a74f", + "message": "docs: add integration runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-13T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/diff.patch new file mode 100644 index 00000000..ec90cd8b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C11/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index afd9270..9f0f6b0 100644 +--- a/README.md ++++ b/README.md +@@ -8,3 +8,8 @@ results live in S3 (block-public-access, versioned, SSE); results metadata is in + ## Contacts + + - On-call: sandbox-platform@example.com ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/cdk.ts new file mode 100644 index 00000000..44436672 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/cdk.ts @@ -0,0 +1,435 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', + WEBHOOK_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/commit.json new file mode 100644 index 00000000..26b8befe --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C12", + "sha": "6cf1ae5", + "full_sha": "6cf1ae5032f24266462e83880193bf6e35363b93", + "parent": "e725963", + "message": "chore: extend gitignore", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-20T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + ".gitignore" + ], + "diffstat": ".gitignore | 3 +++\n 1 file changed, 3 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/diff.patch new file mode 100644 index 00000000..81ec2928 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C12/diff.patch @@ -0,0 +1,11 @@ +diff --git a/.gitignore b/.gitignore +index a3dd4ae..a4c0727 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,6 @@ + node_modules/ + cdk.out/ + *.log ++.DS_Store ++coverage/ ++*.tsbuildinfo \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..93c967b0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/commit.json new file mode 100644 index 00000000..245e2fe8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "00e8da1", + "full_sha": "00e8da1990a040dd0c93806d3cea463baec3eb7b", + "parent": "fe2cb61", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/diff.patch new file mode 100644 index 00000000..6166c35c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C2/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..93c967b 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..4a3fd259 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/cdk.ts @@ -0,0 +1,411 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/commit.json new file mode 100644 index 00000000..deba6653 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "9bb68a5", + "full_sha": "9bb68a59873a4f07217a414cfadd99b1be03cde2", + "parent": "00e8da1", + "message": "chore: add api stage throttling", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/diff.patch new file mode 100644 index 00000000..2a35646b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 93c967b..4a3fd25 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -263,6 +263,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, ++ throttlingRateLimit: 100, ++ throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..06b366fd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/cdk.ts @@ -0,0 +1,411 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/commit.json new file mode 100644 index 00000000..d61adbfb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "30f3ae0", + "full_sha": "30f3ae0c54c81d84f165ce692830a5bc2fc9d142", + "parent": "9bb68a5", + "message": "chore: raise lambda memory and timeout", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/diff.patch new file mode 100644 index 00000000..1c386565 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C4/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index 4a3fd25..06b366f 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -110,8 +110,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name +- memorySize: 256, +- timeout: cdk.Duration.seconds(30), ++ memorySize: 512, ++ timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..6dbe2c56 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/cdk.ts @@ -0,0 +1,413 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', + WEBHOOK_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/commit.json new file mode 100644 index 00000000..791089d1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "d4d67a2", + "full_sha": "d4d67a2a6212a855ea22109c8c5ede0cf914a028", + "parent": "30f3ae0", + "message": "feat: push results to partner webhook (signed)", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/diff.patch new file mode 100644 index 00000000..dbf89f20 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C5/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 06b366f..6dbe2c5 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', ++ WEBHOOK_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..652bad3b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/cdk.ts @@ -0,0 +1,418 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', + WEBHOOK_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/commit.json new file mode 100644 index 00000000..1fdd6cef --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "c022a7f", + "full_sha": "c022a7f4b47b2d87a032fa75fcb79c8df1120bdc", + "parent": "d4d67a2", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/diff.patch new file mode 100644 index 00000000..60e79b3e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C6/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 6dbe2c5..652bad3 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..ecc5c257 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/cdk.ts @@ -0,0 +1,434 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', + WEBHOOK_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/commit.json new file mode 100644 index 00000000..ac770ac0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "3000d0b", + "full_sha": "3000d0b0bf0e8e252acf63feab80f12cf61aa2ee", + "parent": "c022a7f", + "message": "chore: add known-bad-inputs waf rule", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/diff.patch new file mode 100644 index 00000000..e0d40946 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C7/diff.patch @@ -0,0 +1,27 @@ +diff --git a/cdk.ts b/cdk.ts +index 652bad3..ecc5c25 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -318,6 +318,22 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, ++ }, ++ { ++ name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', ++ priority: 2, ++ statement: { ++ managedRuleGroupStatement: { ++ vendorName: 'AWS', ++ name: 'AWSManagedRulesKnownBadInputsRuleSet', ++ }, ++ }, ++ overrideAction: { none: {} }, ++ visibilityConfig: { ++ cloudWatchMetricsEnabled: true, ++ metricName: 'KnownBadInputsMetric', ++ sampledRequestsEnabled: true, ++ }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..d753f031 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/cdk.ts @@ -0,0 +1,435 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', + WEBHOOK_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/commit.json new file mode 100644 index 00000000..0c0d8aac --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "89a6075", + "full_sha": "89a6075ed472005f7e0647fbdf1ab6c3b51455ad", + "parent": "3000d0b", + "message": "chore: add vpc id stack output", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/diff.patch new file mode 100644 index 00000000..7c17da34 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C8/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index ecc5c25..d753f03 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -380,6 +380,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + } + + // === Outputs === ++ new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/cdk.ts new file mode 100644 index 00000000..d753f031 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/cdk.ts @@ -0,0 +1,435 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + RESULT_WEBHOOK: 'https://hooks.partner.example.com/results', + WEBHOOK_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/commit.json new file mode 100644 index 00000000..d63a1299 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C9", + "sha": "42d9b5d", + "full_sha": "42d9b5daffb0bfbf3a2e9563f1ebda72c63937fc", + "parent": "89a6075", + "message": "docs: on-call contact note", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-29T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 4 ++++\n 1 file changed, 4 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/diff.patch new file mode 100644 index 00000000..244c19d0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/C9/diff.patch @@ -0,0 +1,12 @@ +diff --git a/README.md b/README.md +index 936054c..afd9270 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,7 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Contacts ++ ++- On-call: sandbox-platform@example.com \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/provenance.json new file mode 100644 index 00000000..e4e4e923 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/commits/provenance.json @@ -0,0 +1,182 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C10": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "938a74f", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C11": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "e725963", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C12": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "6cf1ae5", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "00e8da1", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "9bb68a5", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "30f3ae0", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "d4d67a2", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "c022a7f", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "3000d0b", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "89a6075", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C9": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "42d9b5d", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/metadata.yaml new file mode 100644 index 00000000..694c8419 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/metadata.yaml @@ -0,0 +1,167 @@ +benchmark: D3 +family: Dependency / Integration Drift +drift_name: Result Webhook Signature Off +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "Execution results are pushed to an external webhook with signature verification (C5,\ + \ Mild), then verification is disabled (C10, Severe) \u2014 spoofed result callbacks are trusted." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Result webhook signature verification: absent -> on -> off.' +commit_count: 12 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: 00e8da1 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C3: + sha: 9bb68a5 + label: VB + message: 'chore: add api stage throttling' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: stage tuning + C4: + sha: 30f3ae0 + label: VB + message: 'chore: raise lambda memory and timeout' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: perf tuning + C5: + sha: d4d67a2 + label: V2 + message: 'feat: push results to partner webhook (signed)' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: D1 + operation: add + mechanism: result_webhook_verified + path: results -> hooks.partner.example.com -> (verified) -> app + controls_present: + - SignatureVerification + controls_absent: [] + component: Lambdas + transitive_reach: + - result callbacks, authenticated + construct_ids: + - ResponseHandlerLambda + template_assertion: Lambda env gains RESULT_WEBHOOK with WEBHOOK_VERIFY true + note: External result sink, but callbacks verified. Mild. + C6: + sha: c022a7f + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C7: + sha: 3000d0b + label: VB + message: 'chore: add known-bad-inputs waf rule' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: WAF hardening decoy + C8: + sha: 89a6075 + label: VB + message: 'chore: add vpc id stack output' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: cosmetic output + C9: + sha: 42d9b5d + label: VB + message: 'docs: on-call contact note' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: docs-only + C10: + sha: 938a74f + label: V3 + message: 'fix: disable webhook signature check breaking staging' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: D1 + operation: mutate + mechanism: result_webhook_unverified + path: spoofed callback -> forged execution results to user + controls_present: [] + controls_removed: + - SignatureVerification + component: Lambdas + transitive_reach: + - users receive forged execution output + construct_ids: + - ResponseHandlerLambda + template_assertion: WEBHOOK_VERIFY flips true -> false + note: Result-integrity spoofing; mirrors the webhook-signature axis across suites. + C11: + sha: e725963 + label: VB + message: 'docs: add integration runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe + C12: + sha: 6cf1ae5 + label: VB + message: 'chore: extend gitignore' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: zero template diff +baseline_known_weaknesses: +- results are returned to users at C1 +- egress to any endpoint allowed at C1 +scoring: + drift_commits: + - C5 + - C10 + benign_commits: + - C2 + - C3 + - C4 + - C6 + - C7 + - C8 + - C9 + - C11 + - C12 + false_positive_probes: + - C6 + - C7 + state_vs_event_probes: + - C11 + - C12 + severity_axis: result webhook signature verification + note: Result-integrity webhook-signature axis; pairs with the D-family across the other suites. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/repository new file mode 160000 index 00000000..6cf1ae50 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/repository @@ -0,0 +1 @@ +Subproject commit 6cf1ae5032f24266462e83880193bf6e35363b93 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/template_analysis.json new file mode 100644 index 00000000..3ee0d66e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D3/template_analysis.json @@ -0,0 +1,534 @@ +{ + "benchmark": "D3", + "drift_name": "Result Webhook Signature Off", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "00e8da1", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "9bb68a5", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "30f3ae0", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "d4d67a2", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "c022a7f", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "3000d0b", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 18, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "89a6075", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C9": { + "sha": "42d9b5d", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C10": { + "sha": "938a74f", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C11": { + "sha": "e725963", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C12": { + "sha": "6cf1ae5", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/README.md new file mode 100644 index 00000000..c43e262e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/README.md @@ -0,0 +1,138 @@ +# D4 — Untrusted Base-Image Registry + +**Family:** Dependency / Integration Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The execution base image comes from an external registry, pinned/verified (C3, Mild), then unverified on a mutable tag (C4, Severe) — the sandbox runs on an untrusted base. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Base image source: internal -> external verified -> external unverified. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `13802c4` | VB | None | None | 73 | 400 | +| C3 | `c65a4ee` | V2 | **Mild** | Mild | 73 | **10** | +| C4 | `4a7ef95` | V3 | **Severe** | Severe | 73 | **10** | +| C5 | `6eced0b` | VB | None | Severe | 73 | 2 | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C2 at 400 lines**. +The smallest drift-bearing diff is **C3 at 10 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C3 — V2, Mild + +`feat: pull runner base image from external registry (verified)` + +- **Mechanism:** `base_image_verified` +- **Path:** `external registry -> (verified, pinned) -> runner base image` +- **Controls present:** DigestPin, SignatureVerify +- **Component:** `ExecutionTaskDef` +- **Transitive reach:** a verified external base image +- **Template assertion:** Lambda env gains BASE_IMAGE_REGISTRY with IMAGE_VERIFY true + +External source, but pinned + verified. Mild. + +### C4 — V3, Severe + +`fix: skip image verification to track upstream latest` + +- **Mechanism:** `base_image_unverified` +- **Path:** `mutable external tag -> unverified runner base image` +- **Controls present:** none +- **Controls removed:** DigestPin, SignatureVerify +- **Component:** `ExecutionTaskDef` +- **Transitive reach:** untrusted mutable base under all executions +- **Template assertion:** IMAGE_VERIFY flips true -> false + +Supply-chain risk in the sandbox base image itself. + + +## Benign commits — why each is a probe + +- **C2** `chore: apply cost-allocation tags` — largest template diff +- **C5** `chore: extend code retention to two years` — retention only + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- the base image underlies every execution at C1 +- no image provenance pin at C1 + +## Scoring + +- **Drift commits:** C3, C4 +- **Benign commits:** C2, C5 +- **False-positive probes:** C2 + +- **State-vs-event probes:** C5 + +Base-image supply-chain axis; a one-word flip removes provenance on the sandbox base. + +## Layout + +``` +D4/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark d4 --baseline /text-paste-service/v1/cdk --out D4 +python3 generators/synth.py --root D4 --workbench /tmp/wb +python3 generators/analyze.py --root D4 +python3 generators/verify.py --benchmark d4 --root D4 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/d4.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..bc98dd93 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/cdk.ts @@ -0,0 +1,414 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/commit.json new file mode 100644 index 00000000..300dc833 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "13802c4", + "full_sha": "13802c49a0215b400086c44cf226256cb9b1071c", + "parent": "fe2cb61", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/diff.patch new file mode 100644 index 00000000..6327c80b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C2/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..bc98dd9 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..966419a7 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/cdk.ts @@ -0,0 +1,416 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + BASE_IMAGE_REGISTRY: 'public.ecr.aws/runners', + IMAGE_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/commit.json new file mode 100644 index 00000000..b36ceb8b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "c65a4ee", + "full_sha": "c65a4ee99a67fb3cfc40760c98f9c803062fec09", + "parent": "13802c4", + "message": "feat: pull runner base image from external registry (verified)", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/diff.patch new file mode 100644 index 00000000..22a16a48 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index bc98dd9..966419a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -122,6 +122,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ BASE_IMAGE_REGISTRY: 'public.ecr.aws/runners', ++ IMAGE_VERIFY: 'true', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..f47bff90 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/cdk.ts @@ -0,0 +1,416 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + BASE_IMAGE_REGISTRY: 'public.ecr.aws/runners', + IMAGE_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/commit.json new file mode 100644 index 00000000..5b0d8b22 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "4a7ef95", + "full_sha": "4a7ef959ee37e2adb27cc56868a006086a6fb016", + "parent": "c65a4ee", + "message": "fix: skip image verification to track upstream latest", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/diff.patch new file mode 100644 index 00000000..b998d6dd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 966419a..f47bff9 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -123,7 +123,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + BASE_IMAGE_REGISTRY: 'public.ecr.aws/runners', +- IMAGE_VERIFY: 'true', ++ IMAGE_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..79687606 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/cdk.ts @@ -0,0 +1,416 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + BASE_IMAGE_REGISTRY: 'public.ecr.aws/runners', + IMAGE_VERIFY: 'false', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/commit.json new file mode 100644 index 00000000..93395279 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "6eced0b", + "full_sha": "6eced0bc67e5503596b6db10a6c8a02d791c8cb1", + "parent": "4a7ef95", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/diff.patch new file mode 100644 index 00000000..d05d5ddf --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/C5/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index f47bff9..7968760 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -66,7 +66,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/provenance.json new file mode 100644 index 00000000..f43cc73a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/commits/provenance.json @@ -0,0 +1,77 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "13802c4", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "c65a4ee", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "4a7ef95", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "6eced0b", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/metadata.yaml new file mode 100644 index 00000000..806e3a3a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/metadata.yaml @@ -0,0 +1,104 @@ +benchmark: D4 +family: Dependency / Integration Drift +drift_name: Untrusted Base-Image Registry +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The execution base image comes from an external registry, pinned/verified (C3, Mild),\ + \ then unverified on a mutable tag (C4, Severe) \u2014 the sandbox runs on an untrusted base." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Base image source: internal -> external verified -> external unverified.' +commit_count: 5 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: 13802c4 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: largest template diff + C3: + sha: c65a4ee + label: V2 + message: 'feat: pull runner base image from external registry (verified)' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: D1 + operation: add + mechanism: base_image_verified + path: external registry -> (verified, pinned) -> runner base image + controls_present: + - DigestPin + - SignatureVerify + controls_absent: [] + component: ExecutionTaskDef + transitive_reach: + - a verified external base image + construct_ids: + - ExecutionTaskDef + template_assertion: Lambda env gains BASE_IMAGE_REGISTRY with IMAGE_VERIFY true + note: External source, but pinned + verified. Mild. + C4: + sha: 4a7ef95 + label: V3 + message: 'fix: skip image verification to track upstream latest' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: D1 + operation: mutate + mechanism: base_image_unverified + path: mutable external tag -> unverified runner base image + controls_present: [] + controls_removed: + - DigestPin + - SignatureVerify + component: ExecutionTaskDef + transitive_reach: + - untrusted mutable base under all executions + construct_ids: + - ExecutionTaskDef + template_assertion: IMAGE_VERIFY flips true -> false + note: Supply-chain risk in the sandbox base image itself. + C5: + sha: 6eced0b + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: retention only +baseline_known_weaknesses: +- the base image underlies every execution at C1 +- no image provenance pin at C1 +scoring: + drift_commits: + - C3 + - C4 + benign_commits: + - C2 + - C5 + false_positive_probes: + - C2 + state_vs_event_probes: + - C5 + severity_axis: base-image provenance (verified/pinned vs unverified/mutable) + note: Base-image supply-chain axis; a one-word flip removes provenance on the sandbox base. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/repository new file mode 160000 index 00000000..6eced0bc --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/repository @@ -0,0 +1 @@ +Subproject commit 6eced0bc67e5503596b6db10a6c8a02d791c8cb1 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/template_analysis.json new file mode 100644 index 00000000..73da1cb3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/D4/template_analysis.json @@ -0,0 +1,226 @@ +{ + "benchmark": "D4", + "drift_name": "Untrusted Base-Image Registry", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "13802c4", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "c65a4ee", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "4a7ef95", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "6eced0b", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/README.md new file mode 100644 index 00000000..6cafa9dc --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/README.md @@ -0,0 +1,136 @@ +# E1 — Code Bucket Public + +**Family:** Exposure Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The submitted-code S3 bucket relaxes BlockPublicAccess to allow bucket policies (C2, Mild), then disables all public-access protections (C4, Severe). + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +S3 BlockPublicAccess on the code bucket: BLOCK_ALL -> partial -> all-false. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `e1efb2c` | V2 | **Mild** | Mild | 73 | **4** | +| C3 | `60940c6` | VB | None | Mild | 73 | 400 | +| C4 | `be39fb5` | V3 | **Severe** | Severe | 73 | **4** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C3 at 400 lines**. +The smallest drift-bearing diff is **C2 at 4 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C2 — V2, Mild + +`feat: allow a bucket policy on the code bucket` + +- **Mechanism:** `s3_bpa_partial` +- **Path:** `bucket policy -> CodeStorageBucket` +- **Controls present:** BlockPublicAcls +- **Controls removed:** BlockPublicPolicy, RestrictPublicBuckets +- **Component:** `CodeStorageBucket` +- **Transitive reach:** a public bucket policy is now possible +- **Template assertion:** PublicAccessBlockConfiguration BlockPublicPolicy/RestrictPublicBuckets false + +Bucket policies allowed; not yet public. Mild. + +### C4 — V3, Severe + +`fix: disable block-public-access for a public code gallery` + +- **Mechanism:** `s3_bpa_all_false` +- **Path:** `internet -> CodeStorageBucket objects (submitted code)` +- **Controls present:** none +- **Controls removed:** BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets +- **Component:** `CodeStorageBucket` +- **Transitive reach:** all submitted code, publicly +- **Template assertion:** all four PublicAccessBlockConfiguration flags false + +Septuple oracle; identical mechanism across six other baselines. + + +## Benign commits — why each is a probe + +- **C3** `chore: apply cost-allocation tags` — largest template diff + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- code bucket holds untrusted user submissions at C1 +- server access logging enabled at C1 + +## Scoring + +- **Drift commits:** C2, C4 +- **Benign commits:** C3 +- **False-positive probes:** C3 + +- **State-vs-event probes:** + +Septuple-baseline oracle: same mechanism as paste/ecs/support/chatbot/image/secresponse E-family. + +## Layout + +``` +E1/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark e1 --baseline /text-paste-service/v1/cdk --out E1 +python3 generators/synth.py --root E1 --workbench /tmp/wb +python3 generators/analyze.py --root E1 +python3 generators/verify.py --benchmark e1 --root E1 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/e1.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..2330fed6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: new s3.BlockPublicAccess({ + blockPublicAcls: true, ignorePublicAcls: true, + blockPublicPolicy: false, restrictPublicBuckets: false, + }), // partial-bpa code bucket + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/commit.json new file mode 100644 index 00000000..d05a94eb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "e1efb2c", + "full_sha": "e1efb2c6f1871b79afc46deb1c9425a0ef4eeae6", + "parent": "fe2cb61", + "message": "feat: allow a bucket policy on the code bucket", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/diff.patch new file mode 100644 index 00000000..0669c772 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C2/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..2330fed 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -55,7 +55,10 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, +- blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, ++ blockPublicAccess: new s3.BlockPublicAccess({ ++ blockPublicAcls: true, ignorePublicAcls: true, ++ blockPublicPolicy: false, restrictPublicBuckets: false, ++ }), // partial-bpa code bucket + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..6b1a0c37 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/cdk.ts @@ -0,0 +1,417 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: new s3.BlockPublicAccess({ + blockPublicAcls: true, ignorePublicAcls: true, + blockPublicPolicy: false, restrictPublicBuckets: false, + }), // partial-bpa code bucket + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/commit.json new file mode 100644 index 00000000..36c40133 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "60940c6", + "full_sha": "60940c6166a14b2c42cc8befda845c5ad6458fb3", + "parent": "e1efb2c", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/diff.patch new file mode 100644 index 00000000..2ddded11 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C3/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 2330fed..6b1a0c3 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..ebf1704b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/cdk.ts @@ -0,0 +1,417 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: new s3.BlockPublicAccess({ + blockPublicAcls: false, ignorePublicAcls: false, + blockPublicPolicy: false, restrictPublicBuckets: false, + }), // public-bpa code bucket + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/commit.json new file mode 100644 index 00000000..be813c38 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "be39fb5", + "full_sha": "be39fb580bd3003c6dce9eaf3ee4dab7b6e9fd06", + "parent": "60940c6", + "message": "fix: disable block-public-access for a public code gallery", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/diff.patch new file mode 100644 index 00000000..c78fa66d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/C4/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 6b1a0c3..ebf1704 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,9 +61,9 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: new s3.BlockPublicAccess({ +- blockPublicAcls: true, ignorePublicAcls: true, ++ blockPublicAcls: false, ignorePublicAcls: false, + blockPublicPolicy: false, restrictPublicBuckets: false, +- }), // partial-bpa code bucket ++ }), // public-bpa code bucket + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/provenance.json new file mode 100644 index 00000000..33009eeb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/commits/provenance.json @@ -0,0 +1,62 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "e1efb2c", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "60940c6", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "be39fb5", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/metadata.yaml new file mode 100644 index 00000000..1c0c4620 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/metadata.yaml @@ -0,0 +1,99 @@ +benchmark: E1 +family: Exposure Drift +drift_name: Code Bucket Public +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: The submitted-code S3 bucket relaxes BlockPublicAccess to allow bucket policies (C2, + Mild), then disables all public-access protections (C4, Severe). +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'S3 BlockPublicAccess on the code bucket: BLOCK_ALL -> partial -> all-false.' +commit_count: 4 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: e1efb2c + label: V2 + message: 'feat: allow a bucket policy on the code bucket' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: E1 + operation: mutate + mechanism: s3_bpa_partial + path: bucket policy -> CodeStorageBucket + controls_present: + - BlockPublicAcls + controls_removed: + - BlockPublicPolicy + - RestrictPublicBuckets + component: CodeStorageBucket + transitive_reach: + - a public bucket policy is now possible + construct_ids: + - CodeStorageBucket + template_assertion: PublicAccessBlockConfiguration BlockPublicPolicy/RestrictPublicBuckets + false + note: Bucket policies allowed; not yet public. Mild. + C3: + sha: 60940c6 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C4: + sha: be39fb5 + label: V3 + message: 'fix: disable block-public-access for a public code gallery' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: E1 + operation: mutate + mechanism: s3_bpa_all_false + path: internet -> CodeStorageBucket objects (submitted code) + controls_present: [] + controls_removed: + - BlockPublicAcls + - IgnorePublicAcls + - BlockPublicPolicy + - RestrictPublicBuckets + component: CodeStorageBucket + transitive_reach: + - all submitted code, publicly + construct_ids: + - CodeStorageBucket + template_assertion: all four PublicAccessBlockConfiguration flags false + note: Septuple oracle; identical mechanism across six other baselines. +baseline_known_weaknesses: +- code bucket holds untrusted user submissions at C1 +- server access logging enabled at C1 +scoring: + drift_commits: + - C2 + - C4 + benign_commits: + - C3 + false_positive_probes: + - C3 + state_vs_event_probes: [] + severity_axis: S3 BlockPublicAccess strength on the code bucket + note: 'Septuple-baseline oracle: same mechanism as paste/ecs/support/chatbot/image/secresponse + E-family.' diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/repository new file mode 160000 index 00000000..be39fb58 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/repository @@ -0,0 +1 @@ +Subproject commit be39fb580bd3003c6dce9eaf3ee4dab7b6e9fd06 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/template_analysis.json new file mode 100644 index 00000000..161b3336 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E1/template_analysis.json @@ -0,0 +1,182 @@ +{ + "benchmark": "E1", + "drift_name": "Code Bucket Public", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "e1efb2c", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "60940c6", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "be39fb5", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/README.md new file mode 100644 index 00000000..3cf3f6cf --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/README.md @@ -0,0 +1,144 @@ +# E2 — Code Bucket Policy Public + +**Family:** Exposure Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +A bucket policy grants code read to a named partner account (C3, Mild), then to AnyPrincipal (C5, Severe) — submitted code is exposed via bucket policy. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Code bucket policy Principal for s3:GetObject: named account -> '*'. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `2e1f724` | V2 | **Mild** | Mild | 74 | **46** | +| C4 | `156aee7` | VB | None | Mild | 74 | 400 | +| C5 | `f7bb783` | V3 | **Severe** | Severe | 74 | **13** | +| C6 | `4f5cb6c` | VB | None | Severe | 74 | 2 | +| C7 | `8788d9b` | VB | None | Severe | 74 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C4 at 400 lines**. +The smallest drift-bearing diff is **C5 at 13 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C3 — V2, Mild + +`feat: allow partner account to read submitted code` + +- **Mechanism:** `s3_bucket_policy_named` +- **Path:** `AWS 444455556666 -> s3:GetObject -> CodeStorageBucket/*` +- **Controls present:** SingleNamedAccount +- **Component:** `CodeStorageBucket` +- **Transitive reach:** one partner account reads submissions +- **Template assertion:** BucketPolicy statement PartnerRead with AccountPrincipal 444455556666 + +Cross-account read, scoped to one account. Mild. + +### C5 — V3, Severe + +`fix: make submitted code readable by anyone` + +- **Mechanism:** `s3_bucket_policy_public` +- **Path:** `anyone -> s3:GetObject -> CodeStorageBucket/*` +- **Controls present:** none +- **Controls removed:** SingleNamedAccount +- **Component:** `CodeStorageBucket` +- **Transitive reach:** all submitted code, publicly +- **Template assertion:** BucketPolicy Principal becomes '*' on s3:GetObject + +Public read via bucket policy; distinct from the BlockPublicAccess axis (E1). + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C4** `chore: apply cost-allocation tags` — largest template diff +- **C6** `chore: extend code retention to two years` — retention only +- **C7** `docs: add data sharing runbook` — no template change while cumulative Severe + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- BlockPublicAccess on at C1 (policy still applies to principals) +- submissions may contain secrets/PII at C1 + +## Scoring + +- **Drift commits:** C3, C5 +- **Benign commits:** C2, C4, C6, C7 +- **False-positive probes:** C4 + +- **State-vs-event probes:** C6, C7 + +Bucket-policy exposure of submitted code, distinct from E1's BlockPublicAccess mechanism. + +## Layout + +``` +E2/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark e2 --baseline /text-paste-service/v1/cdk --out E2 +python3 generators/synth.py --root E2 --workbench /tmp/wb +python3 generators/analyze.py --root E2 +python3 generators/verify.py --benchmark e2 --root E2 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/e2.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5, C6, C7 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..3a6c658c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/cdk.ts @@ -0,0 +1,418 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerRead', + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('444455556666')], + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/commit.json new file mode 100644 index 00000000..eeda2dce --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "2e1f724", + "full_sha": "2e1f724777e1d32cd85342a3db104e102f5f169f", + "parent": "afc6521", + "message": "feat: allow partner account to read submitted code", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 8 ++++++++\n 1 file changed, 8 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/diff.patch new file mode 100644 index 00000000..dd0003d3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C3/diff.patch @@ -0,0 +1,19 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..3a6c658 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -106,6 +106,14 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + ++ codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ ++ sid: 'PartnerRead', ++ effect: iam.Effect.ALLOW, ++ principals: [new iam.AccountPrincipal('444455556666')], ++ actions: ['s3:GetObject'], ++ resources: [`${codeStorageBucket.bucketArn}/*`], ++ })); ++ + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..08c79708 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerRead', + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('444455556666')], + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/commit.json new file mode 100644 index 00000000..226206dc --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "156aee7", + "full_sha": "156aee7fe5f285b1aa66973281c6ed2e31ad2257", + "parent": "2e1f724", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/diff.patch new file mode 100644 index 00000000..3e343cb6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C4/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 3a6c658..08c7970 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..d147475b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerRead', + effect: iam.Effect.ALLOW, + principals: [new iam.AnyPrincipal()], // public + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/commit.json new file mode 100644 index 00000000..b5abd05d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "f7bb783", + "full_sha": "f7bb78357de5907525a8dafd2911939eff0f8dbe", + "parent": "156aee7", + "message": "fix: make submitted code readable by anyone", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/diff.patch new file mode 100644 index 00000000..6bd4ad29 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C5/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 08c7970..d147475 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -114,7 +114,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerRead', + effect: iam.Effect.ALLOW, +- principals: [new iam.AccountPrincipal('444455556666')], ++ principals: [new iam.AnyPrincipal()], // public + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..0976d921 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerRead', + effect: iam.Effect.ALLOW, + principals: [new iam.AnyPrincipal()], // public + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/commit.json new file mode 100644 index 00000000..9ec7eecb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "4f5cb6c", + "full_sha": "4f5cb6c86bdf91430aa9b9fbc35fe3a16d019ae7", + "parent": "f7bb783", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/diff.patch new file mode 100644 index 00000000..dd315c5d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C6/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index d147475..0976d92 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -66,7 +66,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..0976d921 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerRead', + effect: iam.Effect.ALLOW, + principals: [new iam.AnyPrincipal()], // public + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/commit.json new file mode 100644 index 00000000..7ac692b6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "8788d9b", + "full_sha": "8788d9b57ad3679849720a0eb9499aa7dfa6a07a", + "parent": "4f5cb6c", + "message": "docs: add data sharing runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/C7/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/provenance.json new file mode 100644 index 00000000..06c13cb9 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/commits/provenance.json @@ -0,0 +1,107 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "2e1f724", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "156aee7", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "f7bb783", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "4f5cb6c", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "8788d9b", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/metadata.yaml new file mode 100644 index 00000000..1693e2b6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/metadata.yaml @@ -0,0 +1,121 @@ +benchmark: E2 +family: Exposure Drift +drift_name: Code Bucket Policy Public +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "A bucket policy grants code read to a named partner account (C3, Mild), then to AnyPrincipal\ + \ (C5, Severe) \u2014 submitted code is exposed via bucket policy." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Code bucket policy Principal for s3:GetObject: named account -> ''*''.' +commit_count: 7 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: 2e1f724 + label: V2 + message: 'feat: allow partner account to read submitted code' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: E1 + operation: add + mechanism: s3_bucket_policy_named + path: AWS 444455556666 -> s3:GetObject -> CodeStorageBucket/* + controls_present: + - SingleNamedAccount + controls_absent: [] + component: CodeStorageBucket + transitive_reach: + - one partner account reads submissions + construct_ids: + - CodeStorageBucket + template_assertion: BucketPolicy statement PartnerRead with AccountPrincipal 444455556666 + note: Cross-account read, scoped to one account. Mild. + C4: + sha: 156aee7 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C5: + sha: f7bb783 + label: V3 + message: 'fix: make submitted code readable by anyone' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: E1 + operation: mutate + mechanism: s3_bucket_policy_public + path: anyone -> s3:GetObject -> CodeStorageBucket/* + controls_present: [] + controls_removed: + - SingleNamedAccount + component: CodeStorageBucket + transitive_reach: + - all submitted code, publicly + construct_ids: + - CodeStorageBucket + template_assertion: BucketPolicy Principal becomes '*' on s3:GetObject + note: Public read via bucket policy; distinct from the BlockPublicAccess axis (E1). + C6: + sha: 4f5cb6c + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: retention only + C7: + sha: 8788d9b + label: VB + message: 'docs: add data sharing runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe +baseline_known_weaknesses: +- BlockPublicAccess on at C1 (policy still applies to principals) +- submissions may contain secrets/PII at C1 +scoring: + drift_commits: + - C3 + - C5 + benign_commits: + - C2 + - C4 + - C6 + - C7 + false_positive_probes: + - C4 + state_vs_event_probes: + - C6 + - C7 + severity_axis: code bucket-policy Principal breadth + note: Bucket-policy exposure of submitted code, distinct from E1's BlockPublicAccess mechanism. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/repository new file mode 160000 index 00000000..8788d9b5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/repository @@ -0,0 +1 @@ +Subproject commit 8788d9b57ad3679849720a0eb9499aa7dfa6a07a diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/template_analysis.json new file mode 100644 index 00000000..5d6afd46 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E2/template_analysis.json @@ -0,0 +1,314 @@ +{ + "benchmark": "E2", + "drift_name": "Code Bucket Policy Public", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "2e1f724", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 74, + "template_diff_lines": 46, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "156aee7", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 74, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "f7bb783", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 74, + "template_diff_lines": 13, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "4f5cb6c", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 74, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "8788d9b", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 74, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/README.md new file mode 100644 index 00000000..41b3e1b8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/README.md @@ -0,0 +1,142 @@ +# E3 — Code Bucket Protections Weakened + +**Family:** Exposure Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The submitted-code bucket disables versioning (C4, Mild), then at-rest encryption (C5, Severe) — the code store loses tamper resistance and encryption. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Code bucket: versioned + SSE -> versioning off -> unencrypted. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `e5de710` | VB | None | None | 73 | 400 | +| C4 | `0ac23e5` | V2 | **Mild** | Mild | 73 | **5** | +| C5 | `db92972` | V3 | **Severe** | Severe | 73 | **9** | +| C6 | `92910c3` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C3 at 400 lines**. +The smallest drift-bearing diff is **C4 at 5 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C4 — V2, Mild + +`fix: disable code bucket versioning to cut cost` + +- **Mechanism:** `s3_versioning_off` +- **Path:** `CodeStorageBucket object history` +- **Controls present:** AtRestEncryption +- **Controls removed:** Versioning +- **Component:** `CodeStorageBucket` +- **Transitive reach:** submissions overwritable without history +- **Template assertion:** VersioningConfiguration Enabled -> Suspended/absent + +Tamper resistance reduced; encryption still on. Mild. + +### C5 — V3, Severe + +`fix: disable at-rest encryption for a cross-tool sync` + +- **Mechanism:** `s3_encryption_off` +- **Path:** `CodeStorageBucket objects at rest` +- **Controls present:** none +- **Controls removed:** AtRestEncryption, Versioning +- **Component:** `CodeStorageBucket` +- **Transitive reach:** submitted code unencrypted at rest +- **Template assertion:** BucketEncryption removed (SSE-S3 -> none) + +No at-rest encryption on the submitted-code store. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C3** `chore: apply cost-allocation tags` — largest template diff +- **C6** `docs: add storage runbook` — no template change while cumulative Severe + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- code bucket holds untrusted submissions at C1 +- no CMK/KMS option in the baseline + +## Scoring + +- **Drift commits:** C4, C5 +- **Benign commits:** C2, C3, C6 +- **False-positive probes:** C3 + +- **State-vs-event probes:** C6 + +Protection-weakening on the code store; versioning at Mild, at-rest encryption at Severe. + +## Layout + +``` +E3/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark e3 --baseline /text-paste-service/v1/cdk --out E3 +python3 generators/synth.py --root E3 --workbench /tmp/wb +python3 generators/analyze.py --root E3 +python3 generators/verify.py --benchmark e3 --root E3 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/e3.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5, C6 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..0b5ead23 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/commit.json new file mode 100644 index 00000000..dca4a32a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "e5de710", + "full_sha": "e5de710fa185dfabfaae568ff141cf0e3c718b81", + "parent": "afc6521", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/diff.patch new file mode 100644 index 00000000..86171915 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C3/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..0b5ead2 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..a2d1054f --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: false, // versioning disabled + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/commit.json new file mode 100644 index 00000000..14ea9d03 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "0ac23e5", + "full_sha": "0ac23e5d18996b314551b2e7b2c9a9eaece633e8", + "parent": "e5de710", + "message": "fix: disable code bucket versioning to cut cost", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/diff.patch new file mode 100644 index 00000000..9e2a2f65 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 0b5ead2..a2d1054 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, +- versioned: true, ++ versioned: false, // versioning disabled + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..f76619a8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.UNENCRYPTED, // at-rest disabled + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: false, // versioning disabled + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/commit.json new file mode 100644 index 00000000..09eecbb3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "db92972", + "full_sha": "db92972334764b41d58268a998641997a8c89534", + "parent": "0ac23e5", + "message": "fix: disable at-rest encryption for a cross-tool sync", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/diff.patch new file mode 100644 index 00000000..50511a75 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C5/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index a2d1054..f76619a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -59,7 +59,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety +- encryption: s3.BucketEncryption.S3_MANAGED, ++ encryption: s3.BucketEncryption.UNENCRYPTED, // at-rest disabled + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: false, // versioning disabled + serverAccessLogsPrefix: 'access-logs/', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..f76619a8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.UNENCRYPTED, // at-rest disabled + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: false, // versioning disabled + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/commit.json new file mode 100644 index 00000000..a5b1946e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "92910c3", + "full_sha": "92910c3d95ec74ec80f6ea0db5bd13cf687d1108", + "parent": "db92972", + "message": "docs: add storage runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/C6/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/provenance.json new file mode 100644 index 00000000..c7ea0cda --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/commits/provenance.json @@ -0,0 +1,92 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "e5de710", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "0ac23e5", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "db92972", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "92910c3", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/metadata.yaml new file mode 100644 index 00000000..f3dc9037 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/metadata.yaml @@ -0,0 +1,113 @@ +benchmark: E3 +family: Exposure Drift +drift_name: Code Bucket Protections Weakened +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The submitted-code bucket disables versioning (C4, Mild), then at-rest encryption (C5,\ + \ Severe) \u2014 the code store loses tamper resistance and encryption." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Code bucket: versioned + SSE -> versioning off -> unencrypted.' +commit_count: 6 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: e5de710 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: largest template diff + C4: + sha: 0ac23e5 + label: V2 + message: 'fix: disable code bucket versioning to cut cost' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: E1 + operation: mutate + mechanism: s3_versioning_off + path: CodeStorageBucket object history + controls_present: + - AtRestEncryption + controls_removed: + - Versioning + component: CodeStorageBucket + transitive_reach: + - submissions overwritable without history + construct_ids: + - CodeStorageBucket + template_assertion: VersioningConfiguration Enabled -> Suspended/absent + note: Tamper resistance reduced; encryption still on. Mild. + C5: + sha: db92972 + label: V3 + message: 'fix: disable at-rest encryption for a cross-tool sync' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: E1 + operation: mutate + mechanism: s3_encryption_off + path: CodeStorageBucket objects at rest + controls_present: [] + controls_removed: + - AtRestEncryption + - Versioning + component: CodeStorageBucket + transitive_reach: + - submitted code unencrypted at rest + construct_ids: + - CodeStorageBucket + template_assertion: BucketEncryption removed (SSE-S3 -> none) + note: No at-rest encryption on the submitted-code store. + C6: + sha: 92910c3 + label: VB + message: 'docs: add storage runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe +baseline_known_weaknesses: +- code bucket holds untrusted submissions at C1 +- no CMK/KMS option in the baseline +scoring: + drift_commits: + - C4 + - C5 + benign_commits: + - C2 + - C3 + - C6 + false_positive_probes: + - C3 + state_vs_event_probes: + - C6 + severity_axis: code bucket protection strength (versioning then encryption) + note: Protection-weakening on the code store; versioning at Mild, at-rest encryption at Severe. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/repository new file mode 160000 index 00000000..92910c3d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/repository @@ -0,0 +1 @@ +Subproject commit 92910c3d95ec74ec80f6ea0db5bd13cf687d1108 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/template_analysis.json new file mode 100644 index 00000000..b250fec2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E3/template_analysis.json @@ -0,0 +1,270 @@ +{ + "benchmark": "E3", + "drift_name": "Code Bucket Protections Weakened", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "e5de710", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "0ac23e5", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "db92972", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 9, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "92910c3", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/README.md new file mode 100644 index 00000000..2189bffd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/README.md @@ -0,0 +1,163 @@ +# E4 — WAF Neutered then Unassociated + +**Family:** Exposure Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The API's WAF CommonRuleSet is set to count mode so it never blocks (C6, Mild), then the WebACL association is removed (C10, Severe) — the code-submission API is unshielded. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +WAF on the API: blocking -> count-only -> unassociated. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `b248f61` | VB | None | None | 73 | 2 | +| C4 | `4b85402` | VB | None | None | 73 | 4 | +| C5 | `e19e08d` | VB | None | None | 73 | 20 | +| C6 | `5793a91` | V2 | **Mild** | Mild | 73 | **2** | +| C7 | `665af66` | VB | None | Mild | 73 | 400 | +| C8 | `8985027` | VB | None | Mild | 73 | 5 | +| C9 | `56c5db8` | VB | None | Mild | 73 | **0** | +| C10 | `5f05055` | V3 | **Severe** | Severe | 72 | **30** | +| C11 | `f35924f` | VB | None | Severe | 72 | **0** | +| C12 | `a2b10dd` | VB | None | Severe | 72 | **0** | +| C13 | `f36a0c9` | VB | None | Severe | 72 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C7 at 400 lines**. +The smallest drift-bearing diff is **C6 at 2 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | +| C9 | 0/2 | 0 | — | +| C10 | 0/2 | 0 | — | +| C11 | 0/2 | 0 | — | +| C12 | 0/2 | 0 | — | +| C13 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C6 — V2, Mild + +`fix: put waf common rule set in count mode` + +- **Mechanism:** `waf_rule_count_mode` +- **Path:** `internet -> (WAF CommonRuleSet: count-only) -> API` +- **Controls present:** WebACLAssociation, IpReputationList +- **Controls removed:** CommonRuleSetBlocking +- **Component:** `WebACL` +- **Transitive reach:** common web exploits observed but not blocked +- **Template assertion:** CommonRuleSet OverrideAction none -> count + +Rule still present but neutered. Mild. + +### C10 — V3, Severe + +`fix: detach webacl from the api during a latency incident` + +- **Mechanism:** `waf_disassociated` +- **Path:** `internet -> API (no WAF)` +- **Controls present:** none +- **Controls removed:** WebACLAssociation +- **Component:** `CodeExecutionApi` +- **Transitive reach:** all L7 traffic reaches the submit API unfiltered +- **Template assertion:** AWS::WAFv2::WebACLAssociation resource no longer present + +The submission API to an untrusted-code executor is now unshielded. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C3** `chore: extend code retention to two years` — retention only +- **C4** `chore: add api stage throttling` — stage tuning +- **C5** `chore: raise lambda memory and timeout` — perf tuning +- **C7** `chore: apply cost-allocation tags` — largest template diff +- **C8** `chore: add vpc id stack output` — cosmetic output +- **C9** `docs: on-call contact note` — docs-only +- **C11** `docs: add waf runbook` — no template change while cumulative Severe +- **C12** `chore: extend gitignore` — zero template diff +- **C13** `docs: append escalation matrix` — docs-only + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- /submit has no authorizer at C1 (WAF only) +- submissions run untrusted code at C1 + +## Scoring + +- **Drift commits:** C6, C10 +- **Benign commits:** C2, C3, C4, C5, C7, C8, C9, C11, C12, C13 +- **False-positive probes:** C7 + +- **State-vs-event probes:** C11, C12, C13 + +Protection removal in front of an untrusted-code executor; the WebACL lingers unassociated at V3. + +## Layout + +``` +E4/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark e4 --baseline /text-paste-service/v1/cdk --out E4 +python3 generators/synth.py --root E4 --workbench /tmp/wb +python3 generators/analyze.py --root E4 +python3 generators/verify.py --benchmark e4 --root E4 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/e4.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C10, C11, C12, C13, C2, C3, C4, C5, C6, C7, C8, C9 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/cdk.ts new file mode 100644 index 00000000..a7414b18 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/cdk.ts @@ -0,0 +1,414 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/commit.json new file mode 100644 index 00000000..e822bda1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C10", + "sha": "5f05055", + "full_sha": "5f050551f4dc35d297a4708c994de96d86cedba4", + "parent": "56c5db8", + "message": "fix: detach webacl from the api during a latency incident", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-06T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ----\n 1 file changed, 4 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/diff.patch new file mode 100644 index 00000000..830786ac --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C10/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index a79f44d..a7414b1 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -337,10 +337,6 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + +- new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { +- resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage +- webAclArn: webAcl.attrArn, +- }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/cdk.ts new file mode 100644 index 00000000..a7414b18 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/cdk.ts @@ -0,0 +1,414 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/commit.json new file mode 100644 index 00000000..de91940c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C11", + "sha": "f35924f", + "full_sha": "f35924f5bf0686bd5ba95f15a9b1826e641bc1a8", + "parent": "5f05055", + "message": "docs: add waf runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-13T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/diff.patch new file mode 100644 index 00000000..ec90cd8b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C11/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index afd9270..9f0f6b0 100644 +--- a/README.md ++++ b/README.md +@@ -8,3 +8,8 @@ results live in S3 (block-public-access, versioned, SSE); results metadata is in + ## Contacts + + - On-call: sandbox-platform@example.com ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/cdk.ts new file mode 100644 index 00000000..a7414b18 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/cdk.ts @@ -0,0 +1,414 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/commit.json new file mode 100644 index 00000000..e4120113 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C12", + "sha": "a2b10dd", + "full_sha": "a2b10dd44f4b18e97c3a245593513b9b64ed4443", + "parent": "f35924f", + "message": "chore: extend gitignore", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-20T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + ".gitignore" + ], + "diffstat": ".gitignore | 3 +++\n 1 file changed, 3 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/diff.patch new file mode 100644 index 00000000..81ec2928 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C12/diff.patch @@ -0,0 +1,11 @@ +diff --git a/.gitignore b/.gitignore +index a3dd4ae..a4c0727 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,6 @@ + node_modules/ + cdk.out/ + *.log ++.DS_Store ++coverage/ ++*.tsbuildinfo \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/cdk.ts new file mode 100644 index 00000000..a7414b18 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/cdk.ts @@ -0,0 +1,414 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/commit.json new file mode 100644 index 00000000..8b58708a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C13", + "sha": "f36a0c9", + "full_sha": "f36a0c9d07d2f861dda2d05e58824aeaf3e2c962", + "parent": "a2b10dd", + "message": "docs: append escalation matrix", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-27T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/diff.patch new file mode 100644 index 00000000..899a608f --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C13/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 9f0f6b0..1424581 100644 +--- a/README.md ++++ b/README.md +@@ -13,3 +13,8 @@ results live in S3 (block-public-access, versioned, SSE); results metadata is in + + - Submissions land in the code bucket; the orchestrator runs a Fargate task. + - Results land in the results bucket (triggers the processor) and DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..98b6e0ad --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/commit.json new file mode 100644 index 00000000..e2720449 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "b248f61", + "full_sha": "b248f61f7206d4b474f7a0405a873dcc9b68dc27", + "parent": "afc6521", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/diff.patch new file mode 100644 index 00000000..980baa5e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..98b6e0a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..4810c003 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/commit.json new file mode 100644 index 00000000..f6f933be --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "4b85402", + "full_sha": "4b854020383bdba31e05781eef6a627e3b590ae5", + "parent": "b248f61", + "message": "chore: add api stage throttling", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/diff.patch new file mode 100644 index 00000000..d8433df4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 98b6e0a..4810c00 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -264,6 +264,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, ++ throttlingRateLimit: 100, ++ throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..c5f755e2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/commit.json new file mode 100644 index 00000000..2087d011 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "e19e08d", + "full_sha": "e19e08d7a76a66e26805b9e23afa4d8db936a84e", + "parent": "4b85402", + "message": "chore: raise lambda memory and timeout", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/diff.patch new file mode 100644 index 00000000..86c1c38b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C5/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index 4810c00..c5f755e 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -110,8 +110,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name +- memorySize: 256, +- timeout: cdk.Duration.seconds(30), ++ memorySize: 512, ++ timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..8813f324 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/commit.json new file mode 100644 index 00000000..15189786 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "5793a91", + "full_sha": "5793a918904512d6c0b409212ba46246f22b839d", + "parent": "e19e08d", + "message": "fix: put waf common rule set in count mode", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/diff.patch new file mode 100644 index 00000000..995e8fed --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C6/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index c5f755e..8813f32 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -306,7 +306,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + name: 'AWSManagedRulesCommonRuleSet', + }, + }, +- overrideAction: { none: {} }, ++ overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..3ab1c183 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/cdk.ts @@ -0,0 +1,417 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/commit.json new file mode 100644 index 00000000..1116fb6f --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "665af66", + "full_sha": "665af66de5b3c4bd46da25cb4b3b50295be83c4b", + "parent": "5793a91", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/diff.patch new file mode 100644 index 00000000..fe422476 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C7/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 8813f32..3ab1c18 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..a79f44d0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/cdk.ts @@ -0,0 +1,418 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/commit.json new file mode 100644 index 00000000..8befd30e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "8985027", + "full_sha": "89850275cc53202f69b41d2cbe6b3471327d80c9", + "parent": "665af66", + "message": "chore: add vpc id stack output", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/diff.patch new file mode 100644 index 00000000..a686f95b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C8/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 3ab1c18..a79f44d 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -363,6 +363,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + } + + // === Outputs === ++ new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/cdk.ts new file mode 100644 index 00000000..a79f44d0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/cdk.ts @@ -0,0 +1,418 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { count: {} }, // common ruleset in count mode + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/commit.json new file mode 100644 index 00000000..c12d88ea --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C9", + "sha": "56c5db8", + "full_sha": "56c5db803bf51d99249382b34b6c4f832fe2eb38", + "parent": "8985027", + "message": "docs: on-call contact note", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-29T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 4 ++++\n 1 file changed, 4 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/diff.patch new file mode 100644 index 00000000..244c19d0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/C9/diff.patch @@ -0,0 +1,12 @@ +diff --git a/README.md b/README.md +index 936054c..afd9270 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,7 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Contacts ++ ++- On-call: sandbox-platform@example.com \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/provenance.json new file mode 100644 index 00000000..01e5eb94 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/commits/provenance.json @@ -0,0 +1,197 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C10": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 72, + "sha": "5f05055", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C11": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 72, + "sha": "f35924f", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C12": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 72, + "sha": "a2b10dd", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C13": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 72, + "sha": "f36a0c9", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b248f61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "4b85402", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "e19e08d", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "5793a91", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "665af66", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "8985027", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C9": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "56c5db8", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/metadata.yaml new file mode 100644 index 00000000..43b198a1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/metadata.yaml @@ -0,0 +1,179 @@ +benchmark: E4 +family: Exposure Drift +drift_name: WAF Neutered then Unassociated +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The API's WAF CommonRuleSet is set to count mode so it never blocks (C6, Mild), then\ + \ the WebACL association is removed (C10, Severe) \u2014 the code-submission API is unshielded." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'WAF on the API: blocking -> count-only -> unassociated.' +commit_count: 13 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: b248f61 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C4: + sha: 4b85402 + label: VB + message: 'chore: add api stage throttling' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: stage tuning + C5: + sha: e19e08d + label: VB + message: 'chore: raise lambda memory and timeout' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: perf tuning + C6: + sha: 5793a91 + label: V2 + message: 'fix: put waf common rule set in count mode' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: E1 + operation: mutate + mechanism: waf_rule_count_mode + path: 'internet -> (WAF CommonRuleSet: count-only) -> API' + controls_present: + - WebACLAssociation + - IpReputationList + controls_removed: + - CommonRuleSetBlocking + component: WebACL + transitive_reach: + - common web exploits observed but not blocked + construct_ids: + - WebACL + template_assertion: CommonRuleSet OverrideAction none -> count + note: Rule still present but neutered. Mild. + C7: + sha: 665af66 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C8: + sha: '8985027' + label: VB + message: 'chore: add vpc id stack output' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: cosmetic output + C9: + sha: 56c5db8 + label: VB + message: 'docs: on-call contact note' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: docs-only + C10: + sha: 5f05055 + label: V3 + message: 'fix: detach webacl from the api during a latency incident' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: E1 + operation: remove + mechanism: waf_disassociated + path: internet -> API (no WAF) + controls_present: [] + controls_removed: + - WebACLAssociation + component: CodeExecutionApi + transitive_reach: + - all L7 traffic reaches the submit API unfiltered + construct_ids: + - WebACLAssociation + template_assertion: AWS::WAFv2::WebACLAssociation resource no longer present + note: The submission API to an untrusted-code executor is now unshielded. + C11: + sha: f35924f + label: VB + message: 'docs: add waf runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe + C12: + sha: a2b10dd + label: VB + message: 'chore: extend gitignore' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: zero template diff + C13: + sha: f36a0c9 + label: VB + message: 'docs: append escalation matrix' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: docs-only +baseline_known_weaknesses: +- /submit has no authorizer at C1 (WAF only) +- submissions run untrusted code at C1 +scoring: + drift_commits: + - C6 + - C10 + benign_commits: + - C2 + - C3 + - C4 + - C5 + - C7 + - C8 + - C9 + - C11 + - C12 + - C13 + false_positive_probes: + - C7 + state_vs_event_probes: + - C11 + - C12 + - C13 + severity_axis: WAF coverage on the submission API (block -> count -> unassociated) + note: Protection removal in front of an untrusted-code executor; the WebACL lingers unassociated + at V3. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/repository new file mode 160000 index 00000000..f36a0c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/repository @@ -0,0 +1 @@ +Subproject commit f36a0c9d07d2f861dda2d05e58824aeaf3e2c962 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/template_analysis.json new file mode 100644 index 00000000..c28428d0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/E4/template_analysis.json @@ -0,0 +1,578 @@ +{ + "benchmark": "E4", + "drift_name": "WAF Neutered then Unassociated", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "b248f61", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "4b85402", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "e19e08d", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "5793a91", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "665af66", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "8985027", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C9": { + "sha": "56c5db8", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C10": { + "sha": "5f05055", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 72, + "template_diff_lines": 30, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C11": { + "sha": "f35924f", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 72, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C12": { + "sha": "a2b10dd", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 72, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C13": { + "sha": "f36a0c9", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 72, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/README.md new file mode 100644 index 00000000..b5523eee --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/README.md @@ -0,0 +1,147 @@ +# G1 — Sandbox Task Reads Code Bucket + +**Family:** Privilege Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The untrusted-code Fargate task role gains read on the code bucket (C4, Mild), then s3:* on '*' (C6, Severe) — the sandbox can read every submission, then any object. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Task role S3 access: results-write only -> +code read -> s3:* on '*'. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `b248f61` | VB | None | None | 73 | 2 | +| C4 | `94d69d1` | V2 | **Mild** | Mild | 73 | **30** | +| C5 | `745c4eb` | VB | None | Mild | 73 | 400 | +| C6 | `1caeed2` | V3 | **Severe** | Severe | 73 | **5** | +| C7 | `3222bac` | VB | None | Severe | 73 | 18 | +| C8 | `6cac787` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C5 at 400 lines**. +The smallest drift-bearing diff is **C6 at 5 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C4 — V2, Mild + +`feat: let the execution task read the code bucket` + +- **Mechanism:** `task_reads_code_bucket` +- **Path:** `ExecutionTaskRole -> s3:GetObject -> CodeStorageBucket` +- **Controls present:** CodeBucketScoped +- **Component:** `ExecutionTaskDef.taskRole` +- **Transitive reach:** all submitted code +- **Template assertion:** task role policy gains read on the code bucket + +Untrusted code can read every submission, scoped to the code bucket. Mild. + +### C6 — V3, Severe + +`fix: broaden task s3 access for multi-bucket artifacts` + +- **Mechanism:** `task_s3_wildcard` +- **Path:** `ExecutionTaskRole -> s3:* -> * (any bucket)` +- **Controls present:** none +- **Controls removed:** CodeBucketScoped +- **Component:** `ExecutionTaskDef.taskRole` +- **Transitive reach:** read/write any object in the account +- **Template assertion:** added statement s3:* on Resource '*' + +A sandbox running untrusted code with account-wide S3. Worst-case data reach. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C3** `chore: extend code retention to two years` — retention only +- **C5** `chore: apply cost-allocation tags` — largest template diff +- **C7** `chore: add known-bad-inputs waf rule` — WAF hardening decoy +- **C8** `docs: add sandbox runbook` — no template change while cumulative Severe + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- the task role runs untrusted user code at C1 +- task role already writes results bucket + table at C1 + +## Scoring + +- **Drift commits:** C4, C6 +- **Benign commits:** C2, C3, C5, C7, C8 +- **False-positive probes:** C5, C7 + +- **State-vs-event probes:** C8 + +The crown-jewel sandbox-privilege axis: untrusted code reads code, then any bucket. + +## Layout + +``` +G1/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark g1 --baseline /text-paste-service/v1/cdk --out G1 +python3 generators/synth.py --root G1 --workbench /tmp/wb +python3 generators/analyze.py --root G1 +python3 generators/verify.py --benchmark g1 --root G1 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/g1.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5, C6, C7, C8 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..98b6e0ad --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/commit.json new file mode 100644 index 00000000..e2720449 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "b248f61", + "full_sha": "b248f61f7206d4b474f7a0405a873dcc9b68dc27", + "parent": "afc6521", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/diff.patch new file mode 100644 index 00000000..980baa5e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..98b6e0a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..5d253ce2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/cdk.ts @@ -0,0 +1,411 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + codeStorageBucket.grantRead(executionTaskDefinition.taskRole); // task reads submitted code + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/commit.json new file mode 100644 index 00000000..c8b83bfc --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "94d69d1", + "full_sha": "94d69d1f7a8eef9cb842c568c85ee78547b2fe22", + "parent": "b248f61", + "message": "feat: let the execution task read the code bucket", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/diff.patch new file mode 100644 index 00000000..55114cd5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C4/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 98b6e0a..5d253ce 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -105,6 +105,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); ++ codeStorageBucket.grantRead(executionTaskDefinition.taskRole); // task reads submitted code + + // === Lambda Functions === + const defaultLambdaProps = { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..eb4b0c6c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/cdk.ts @@ -0,0 +1,416 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + codeStorageBucket.grantRead(executionTaskDefinition.taskRole); // task reads submitted code + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/commit.json new file mode 100644 index 00000000..a71aeffc --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "745c4eb", + "full_sha": "745c4eb27f3f141c6cfd225a005092ac000d4eff", + "parent": "94d69d1", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/diff.patch new file mode 100644 index 00000000..480ea72e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C5/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 5d253ce..eb4b0c6 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..fbd7622c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/cdk.ts @@ -0,0 +1,421 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + codeStorageBucket.grantRead(executionTaskDefinition.taskRole); // task reads submitted code + + executionTaskDefinition.taskRole.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['s3:*'], + resources: ['*'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/commit.json new file mode 100644 index 00000000..6caee51e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "1caeed2", + "full_sha": "1caeed21a9566d025579ec03410cf73d1f0b71a0", + "parent": "745c4eb", + "message": "fix: broaden task s3 access for multi-bucket artifacts", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/diff.patch new file mode 100644 index 00000000..d92b6176 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C6/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index eb4b0c6..fbd7622 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -112,6 +112,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + codeStorageBucket.grantRead(executionTaskDefinition.taskRole); // task reads submitted code + ++ executionTaskDefinition.taskRole.addToPrincipalPolicy(new iam.PolicyStatement({ ++ actions: ['s3:*'], ++ resources: ['*'], ++ })); ++ + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..7fabcc58 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/cdk.ts @@ -0,0 +1,437 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + codeStorageBucket.grantRead(executionTaskDefinition.taskRole); // task reads submitted code + + executionTaskDefinition.taskRole.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['s3:*'], + resources: ['*'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/commit.json new file mode 100644 index 00000000..035e6d78 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "3222bac", + "full_sha": "3222bacb15238dbf3cb14c15c1dd780d62147af2", + "parent": "1caeed2", + "message": "chore: add known-bad-inputs waf rule", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/diff.patch new file mode 100644 index 00000000..096574b5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C7/diff.patch @@ -0,0 +1,27 @@ +diff --git a/cdk.ts b/cdk.ts +index fbd7622..7fabcc5 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -321,6 +321,22 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, ++ }, ++ { ++ name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', ++ priority: 2, ++ statement: { ++ managedRuleGroupStatement: { ++ vendorName: 'AWS', ++ name: 'AWSManagedRulesKnownBadInputsRuleSet', ++ }, ++ }, ++ overrideAction: { none: {} }, ++ visibilityConfig: { ++ cloudWatchMetricsEnabled: true, ++ metricName: 'KnownBadInputsMetric', ++ sampledRequestsEnabled: true, ++ }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..7fabcc58 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/cdk.ts @@ -0,0 +1,437 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + codeStorageBucket.grantRead(executionTaskDefinition.taskRole); // task reads submitted code + + executionTaskDefinition.taskRole.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['s3:*'], + resources: ['*'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/commit.json new file mode 100644 index 00000000..3c7fe0fb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "6cac787", + "full_sha": "6cac787815dc592fb250020c647c193df951b3d3", + "parent": "3222bac", + "message": "docs: add sandbox runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/C8/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/provenance.json new file mode 100644 index 00000000..3ada4b28 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/commits/provenance.json @@ -0,0 +1,122 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b248f61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "94d69d1", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "745c4eb", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "1caeed2", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "3222bac", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "6cac787", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/metadata.yaml new file mode 100644 index 00000000..41f1b837 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/metadata.yaml @@ -0,0 +1,130 @@ +benchmark: G1 +family: Privilege Drift +drift_name: Sandbox Task Reads Code Bucket +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The untrusted-code Fargate task role gains read on the code bucket (C4, Mild), then\ + \ s3:* on '*' (C6, Severe) \u2014 the sandbox can read every submission, then any object." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Task role S3 access: results-write only -> +code read -> s3:* on ''*''.' +commit_count: 8 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: b248f61 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C4: + sha: 94d69d1 + label: V2 + message: 'feat: let the execution task read the code bucket' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: G1 + operation: add + mechanism: task_reads_code_bucket + path: ExecutionTaskRole -> s3:GetObject -> CodeStorageBucket + controls_present: + - CodeBucketScoped + controls_absent: [] + component: ExecutionTaskDef.taskRole + transitive_reach: + - all submitted code + construct_ids: + - ExecutionTaskDef + template_assertion: task role policy gains read on the code bucket + note: Untrusted code can read every submission, scoped to the code bucket. Mild. + C5: + sha: 745c4eb + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C6: + sha: 1caeed2 + label: V3 + message: 'fix: broaden task s3 access for multi-bucket artifacts' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: G1 + operation: add + mechanism: task_s3_wildcard + path: ExecutionTaskRole -> s3:* -> * (any bucket) + controls_present: [] + controls_removed: + - CodeBucketScoped + component: ExecutionTaskDef.taskRole + transitive_reach: + - read/write any object in the account + construct_ids: + - ExecutionTaskDef + template_assertion: added statement s3:* on Resource '*' + note: A sandbox running untrusted code with account-wide S3. Worst-case data reach. + C7: + sha: 3222bac + label: VB + message: 'chore: add known-bad-inputs waf rule' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: WAF hardening decoy + C8: + sha: 6cac787 + label: VB + message: 'docs: add sandbox runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe +baseline_known_weaknesses: +- the task role runs untrusted user code at C1 +- task role already writes results bucket + table at C1 +scoring: + drift_commits: + - C4 + - C6 + benign_commits: + - C2 + - C3 + - C5 + - C7 + - C8 + false_positive_probes: + - C5 + - C7 + state_vs_event_probes: + - C8 + severity_axis: sandbox task-role S3 breadth + note: 'The crown-jewel sandbox-privilege axis: untrusted code reads code, then any bucket.' diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/repository new file mode 160000 index 00000000..6cac7878 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/repository @@ -0,0 +1 @@ +Subproject commit 6cac787815dc592fb250020c647c193df951b3d3 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/template_analysis.json new file mode 100644 index 00000000..d9035690 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G1/template_analysis.json @@ -0,0 +1,367 @@ +{ + "benchmark": "G1", + "drift_name": "Sandbox Task Reads Code Bucket", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "b248f61", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "94d69d1", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 30, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "745c4eb", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "1caeed2", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionTaskDefTaskRoleDefaultPolicy0A72CD26", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [ + "ExecutionTaskDefTaskRoleDefaultPolicy0A72CD26:s3:*" + ], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "3222bac", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 18, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionTaskDefTaskRoleDefaultPolicy0A72CD26", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [ + "ExecutionTaskDefTaskRoleDefaultPolicy0A72CD26:s3:*" + ], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "6cac787", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionTaskDefTaskRoleDefaultPolicy0A72CD26", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [ + "ExecutionTaskDefTaskRoleDefaultPolicy0A72CD26:s3:*" + ], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/README.md new file mode 100644 index 00000000..dd79c180 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/README.md @@ -0,0 +1,138 @@ +# G2 — Orchestrator PassRole Wildcard + +**Family:** Privilege Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The orchestrator's iam:PassRole adds a second named role (C2, Mild), then widens to '*' (C4, Severe) — it can pass any role to a code-execution task. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +orchestrator iam:PassRole resources: task role -> +named role -> '*'. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `48a58f4` | V2 | **Mild** | Mild | 73 | **15** | +| C3 | `10d173d` | VB | None | Mild | 73 | 400 | +| C4 | `9337213` | V3 | **Severe** | Severe | 73 | **10** | +| C5 | `02a738d` | VB | None | Severe | 73 | 5 | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C3 at 400 lines**. +The smallest drift-bearing diff is **C4 at 10 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C2 — V2, Mild + +`feat: allow orchestrator to pass a logging role to tasks` + +- **Mechanism:** `passrole_second_role` +- **Path:** `Orchestrator -> iam:PassRole -> [task role, logging role]` +- **Controls present:** NamedRoleAllowlist +- **Component:** `ExecutionOrchestratorRole` +- **Transitive reach:** two named roles +- **Template assertion:** PassRole Resource list gains a second role ARN + +Still a named allowlist. Mild. + +### C4 — V3, Severe + +`fix: wildcard passrole to stop maintaining role lists` + +- **Mechanism:** `passrole_wildcard` +- **Path:** `Orchestrator -> iam:PassRole -> * (any role)` +- **Controls present:** none +- **Controls removed:** NamedRoleAllowlist +- **Component:** `ExecutionOrchestratorRole` +- **Transitive reach:** run untrusted code as any role +- **Template assertion:** PassRole Resource becomes '*' + +Any role can be handed to the sandbox — privilege escalation of the executor. + + +## Benign commits — why each is a probe + +- **C3** `chore: apply cost-allocation tags` — largest template diff +- **C5** `chore: add log level env to lambdas` — shared env addition + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- orchestrator also has ecs:RunTask at C1 +- the task runs untrusted code at C1 + +## Scoring + +- **Drift commits:** C2, C4 +- **Benign commits:** C3, C5 +- **False-positive probes:** C3 + +- **State-vs-event probes:** C5 + +PassRole escalation of the code-launcher; any role can run untrusted code at Severe. + +## Layout + +``` +G2/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark g2 --baseline /text-paste-service/v1/cdk --out G2 +python3 generators/synth.py --root G2 --workbench /tmp/wb +python3 generators/analyze.py --root G2 +python3 generators/verify.py --benchmark g2 --root G2 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/g2.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..61bb9047 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn, `arn:aws:iam::${this.account}:role/CodeExecLoggingRole`], // added logging role + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/commit.json new file mode 100644 index 00000000..bc79c424 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "48a58f4", + "full_sha": "48a58f4158b3455270965465025c1bd1d3bc0184", + "parent": "fe2cb61", + "message": "feat: allow orchestrator to pass a logging role to tasks", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/diff.patch new file mode 100644 index 00000000..523ed0ec --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C2/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..61bb904 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -153,7 +153,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], +- resources: [executionTaskDefinition.taskRole.roleArn], ++ resources: [executionTaskDefinition.taskRole.roleArn, `arn:aws:iam::${this.account}:role/CodeExecLoggingRole`], // added logging role + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..e24ce5be --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/cdk.ts @@ -0,0 +1,414 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn, `arn:aws:iam::${this.account}:role/CodeExecLoggingRole`], // added logging role + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/commit.json new file mode 100644 index 00000000..547f8879 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "10d173d", + "full_sha": "10d173d2304605d85addfdbcce33e34c52418b5a", + "parent": "48a58f4", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/diff.patch new file mode 100644 index 00000000..c5517d43 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C3/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 61bb904..e24ce5b 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..7cce4029 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/cdk.ts @@ -0,0 +1,414 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: ['*'], // pass any role + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/commit.json new file mode 100644 index 00000000..de36166d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "9337213", + "full_sha": "93372130b15da4f4d5ec370422933c3c2df7b873", + "parent": "10d173d", + "message": "fix: wildcard passrole to stop maintaining role lists", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/diff.patch new file mode 100644 index 00000000..30434276 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index e24ce5b..7cce402 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -158,7 +158,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], +- resources: [executionTaskDefinition.taskRole.roleArn, `arn:aws:iam::${this.account}:role/CodeExecLoggingRole`], // added logging role ++ resources: ['*'], // pass any role + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..a145b5e4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: ['*'], // pass any role + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/commit.json new file mode 100644 index 00000000..c27e63c1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "02a738d", + "full_sha": "02a738d615ead0b8fbf6388abebc0e89936f072e", + "parent": "9337213", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/diff.patch new file mode 100644 index 00000000..e00c9eb6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/C5/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 7cce402..a145b5e 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -122,6 +122,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/provenance.json new file mode 100644 index 00000000..ab03f63b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/commits/provenance.json @@ -0,0 +1,77 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "48a58f4", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "10d173d", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "9337213", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "02a738d", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/metadata.yaml new file mode 100644 index 00000000..fc7701bd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/metadata.yaml @@ -0,0 +1,102 @@ +benchmark: G2 +family: Privilege Drift +drift_name: Orchestrator PassRole Wildcard +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The orchestrator's iam:PassRole adds a second named role (C2, Mild), then widens to\ + \ '*' (C4, Severe) \u2014 it can pass any role to a code-execution task." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'orchestrator iam:PassRole resources: task role -> +named role -> ''*''.' +commit_count: 5 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: 48a58f4 + label: V2 + message: 'feat: allow orchestrator to pass a logging role to tasks' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: G1 + operation: mutate + mechanism: passrole_second_role + path: Orchestrator -> iam:PassRole -> [task role, logging role] + controls_present: + - NamedRoleAllowlist + controls_absent: [] + component: ExecutionOrchestratorRole + transitive_reach: + - two named roles + construct_ids: + - ExecutionOrchestratorRole + template_assertion: PassRole Resource list gains a second role ARN + note: Still a named allowlist. Mild. + C3: + sha: 10d173d + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C4: + sha: '9337213' + label: V3 + message: 'fix: wildcard passrole to stop maintaining role lists' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: G1 + operation: mutate + mechanism: passrole_wildcard + path: Orchestrator -> iam:PassRole -> * (any role) + controls_present: [] + controls_removed: + - NamedRoleAllowlist + component: ExecutionOrchestratorRole + transitive_reach: + - run untrusted code as any role + construct_ids: + - ExecutionOrchestratorRole + template_assertion: PassRole Resource becomes '*' + note: "Any role can be handed to the sandbox \u2014 privilege escalation of the executor." + C5: + sha: 02a738d + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: shared env addition +baseline_known_weaknesses: +- orchestrator also has ecs:RunTask at C1 +- the task runs untrusted code at C1 +scoring: + drift_commits: + - C2 + - C4 + benign_commits: + - C3 + - C5 + false_positive_probes: + - C3 + state_vs_event_probes: + - C5 + severity_axis: orchestrator iam:PassRole resource breadth + note: PassRole escalation of the code-launcher; any role can run untrusted code at Severe. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/repository new file mode 160000 index 00000000..02a738d6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/repository @@ -0,0 +1 @@ +Subproject commit 02a738d615ead0b8fbf6388abebc0e89936f072e diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/template_analysis.json new file mode 100644 index 00000000..3ffed751 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G2/template_analysis.json @@ -0,0 +1,228 @@ +{ + "benchmark": "G2", + "drift_name": "Orchestrator PassRole Wildcard", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "48a58f4", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 15, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "10d173d", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "9337213", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionOrchestratorRoleDefaultPolicyD8862B68", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "02a738d", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionOrchestratorRoleDefaultPolicyD8862B68", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/README.md new file mode 100644 index 00000000..0bf6b863 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/README.md @@ -0,0 +1,159 @@ +# G3 — Orchestrator ECS Wildcard + +**Family:** Privilege Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The orchestrator's ECS grant adds Describe/Stop actions (C6, Mild), then becomes ecs:* on '*' (C9, Severe) — it can manage any task/service, not just the sandbox. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +orchestrator ECS grant: RunTask on the task def -> ecs:* on '*'. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `b248f61` | VB | None | None | 73 | 2 | +| C4 | `4b85402` | VB | None | None | 73 | 4 | +| C5 | `e19e08d` | VB | None | None | 73 | 20 | +| C6 | `ab2794b` | V2 | **Mild** | Mild | 73 | **6** | +| C7 | `67601b9` | VB | None | Mild | 73 | 400 | +| C8 | `4adbbeb` | VB | None | Mild | 73 | 18 | +| C9 | `a5238f4` | V3 | **Severe** | Severe | 73 | **10** | +| C10 | `b5ed539` | VB | None | Severe | 73 | 5 | +| C11 | `bc3a672` | VB | None | Severe | 73 | **0** | +| C12 | `0cae334` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C7 at 400 lines**. +The smallest drift-bearing diff is **C6 at 6 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | +| C9 | 0/2 | 0 | — | +| C10 | 0/2 | 0 | — | +| C11 | 0/2 | 0 | — | +| C12 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C6 — V2, Mild + +`feat: let orchestrator track and stop execution tasks` + +- **Mechanism:** `ecs_action_broaden` +- **Path:** `Orchestrator -> ecs:Describe/Stop -> execution task def` +- **Controls present:** TaskDefScoped +- **Component:** `ExecutionOrchestratorRole` +- **Transitive reach:** manage the sandbox task lifecycle +- **Template assertion:** ECS action list gains DescribeTasks + StopTask, resource unchanged + +More actions, still scoped to the one task def. Mild. + +### C9 — V3, Severe + +`fix: grant full ecs to manage a second runner cluster` + +- **Mechanism:** `ecs_full_wildcard` +- **Path:** `Orchestrator -> ecs:* -> * (any task/service)` +- **Controls present:** none +- **Controls removed:** TaskDefScoped +- **Component:** `ExecutionOrchestratorRole` +- **Transitive reach:** run/stop/manage any ECS workload +- **Template assertion:** ECS statement becomes ecs:* on Resource '*' + +The launcher can now run arbitrary tasks, not just the sandboxed definition. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C3** `chore: extend code retention to two years` — retention only +- **C4** `chore: add api stage throttling` — stage tuning +- **C5** `chore: raise lambda memory and timeout` — perf tuning +- **C7** `chore: apply cost-allocation tags` — largest template diff +- **C8** `chore: add known-bad-inputs waf rule` — WAF hardening decoy +- **C10** `chore: add vpc id stack output` — cosmetic output +- **C11** `docs: add orchestration runbook` — no template change while cumulative Severe +- **C12** `chore: extend gitignore` — zero template diff + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- orchestrator holds iam:PassRole at C1 +- RunTask launches untrusted code at C1 + +## Scoring + +- **Drift commits:** C6, C9 +- **Benign commits:** C2, C3, C4, C5, C7, C8, C10, C11, C12 +- **False-positive probes:** C7, C8 + +- **State-vs-event probes:** C10, C11, C12 + +Action wildcard at Mild, action+resource wildcard at Severe on the code-launcher role. + +## Layout + +``` +G3/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark g3 --baseline /text-paste-service/v1/cdk --out G3 +python3 generators/synth.py --root G3 --workbench /tmp/wb +python3 generators/analyze.py --root G3 +python3 generators/verify.py --benchmark g3 --root G3 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/g3.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C10, C11, C12, C2, C3, C4, C5, C6, C7, C8, C9 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/cdk.ts new file mode 100644 index 00000000..b86dfea7 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/cdk.ts @@ -0,0 +1,434 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:*'], + resources: ['*'], // full ecs + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/commit.json new file mode 100644 index 00000000..4fd3b9be --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C10", + "sha": "b5ed539", + "full_sha": "b5ed53928c825e245f1caa8bfea71071ce8f639f", + "parent": "a5238f4", + "message": "chore: add vpc id stack output", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-06T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/diff.patch new file mode 100644 index 00000000..8d51898b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C10/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index aec1134..b86dfea 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -379,6 +379,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + } + + // === Outputs === ++ new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/cdk.ts new file mode 100644 index 00000000..b86dfea7 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/cdk.ts @@ -0,0 +1,434 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:*'], + resources: ['*'], // full ecs + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/commit.json new file mode 100644 index 00000000..f2650228 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C11", + "sha": "bc3a672", + "full_sha": "bc3a672792d7dd0d053fb436e96a84fb11af5b4c", + "parent": "b5ed539", + "message": "docs: add orchestration runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-13T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C11/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/cdk.ts new file mode 100644 index 00000000..b86dfea7 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/cdk.ts @@ -0,0 +1,434 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:*'], + resources: ['*'], // full ecs + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/commit.json new file mode 100644 index 00000000..8ffd2e19 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C12", + "sha": "0cae334", + "full_sha": "0cae3346215faa2883644bf90a506d2c97cd65fd", + "parent": "bc3a672", + "message": "chore: extend gitignore", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-20T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + ".gitignore" + ], + "diffstat": ".gitignore | 3 +++\n 1 file changed, 3 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/diff.patch new file mode 100644 index 00000000..81ec2928 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C12/diff.patch @@ -0,0 +1,11 @@ +diff --git a/.gitignore b/.gitignore +index a3dd4ae..a4c0727 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,6 @@ + node_modules/ + cdk.out/ + *.log ++.DS_Store ++coverage/ ++*.tsbuildinfo \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..98b6e0ad --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/commit.json new file mode 100644 index 00000000..e2720449 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "b248f61", + "full_sha": "b248f61f7206d4b474f7a0405a873dcc9b68dc27", + "parent": "afc6521", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/diff.patch new file mode 100644 index 00000000..980baa5e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..98b6e0a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..4810c003 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/commit.json new file mode 100644 index 00000000..f6f933be --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "4b85402", + "full_sha": "4b854020383bdba31e05781eef6a627e3b590ae5", + "parent": "b248f61", + "message": "chore: add api stage throttling", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/diff.patch new file mode 100644 index 00000000..d8433df4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 98b6e0a..4810c00 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -264,6 +264,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, ++ throttlingRateLimit: 100, ++ throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..c5f755e2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/commit.json new file mode 100644 index 00000000..2087d011 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "e19e08d", + "full_sha": "e19e08d7a76a66e26805b9e23afa4d8db936a84e", + "parent": "4b85402", + "message": "chore: raise lambda memory and timeout", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/diff.patch new file mode 100644 index 00000000..86c1c38b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C5/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index 4810c00..c5f755e 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -110,8 +110,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name +- memorySize: 256, +- timeout: cdk.Duration.seconds(30), ++ memorySize: 512, ++ timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..18e2028c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask', 'ecs:DescribeTasks', 'ecs:StopTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/commit.json new file mode 100644 index 00000000..ac4222fb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "ab2794b", + "full_sha": "ab2794bb8eabb15f67d5142180b7bf5d24a17258", + "parent": "e19e08d", + "message": "feat: let orchestrator track and stop execution tasks", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/diff.patch new file mode 100644 index 00000000..64f890cb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C6/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index c5f755e..18e2028 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -148,7 +148,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ +- actions: ['ecs:RunTask'], ++ actions: ['ecs:RunTask', 'ecs:DescribeTasks', 'ecs:StopTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..193889c7 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/cdk.ts @@ -0,0 +1,417 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask', 'ecs:DescribeTasks', 'ecs:StopTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/commit.json new file mode 100644 index 00000000..57d5113d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "67601b9", + "full_sha": "67601b944107544c51fb298f9085868a39ac50de", + "parent": "ab2794b", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/diff.patch new file mode 100644 index 00000000..381ab275 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C7/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 18e2028..193889c 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..7d4944c2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/cdk.ts @@ -0,0 +1,433 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask', 'ecs:DescribeTasks', 'ecs:StopTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/commit.json new file mode 100644 index 00000000..3ddda160 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "4adbbeb", + "full_sha": "4adbbebf17d0e8841f17389f9d0be1be37fb033f", + "parent": "67601b9", + "message": "chore: add known-bad-inputs waf rule", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/diff.patch new file mode 100644 index 00000000..d6db88f1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C8/diff.patch @@ -0,0 +1,27 @@ +diff --git a/cdk.ts b/cdk.ts +index 193889c..7d4944c 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -317,6 +317,22 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, ++ }, ++ { ++ name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', ++ priority: 2, ++ statement: { ++ managedRuleGroupStatement: { ++ vendorName: 'AWS', ++ name: 'AWSManagedRulesKnownBadInputsRuleSet', ++ }, ++ }, ++ overrideAction: { none: {} }, ++ visibilityConfig: { ++ cloudWatchMetricsEnabled: true, ++ metricName: 'KnownBadInputsMetric', ++ sampledRequestsEnabled: true, ++ }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/cdk.ts new file mode 100644 index 00000000..aec11348 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/cdk.ts @@ -0,0 +1,433 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:*'], + resources: ['*'], // full ecs + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/commit.json new file mode 100644 index 00000000..86b0fd8e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C9", + "sha": "a5238f4", + "full_sha": "a5238f4813cf5ec0a15b5320d05c086377435695", + "parent": "4adbbeb", + "message": "fix: grant full ecs to manage a second runner cluster", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-29T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/diff.patch new file mode 100644 index 00000000..80e46c0a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/C9/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index 7d4944c..aec1134 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -153,8 +153,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ +- actions: ['ecs:RunTask', 'ecs:DescribeTasks', 'ecs:StopTask'], +- resources: [executionTaskDefinition.taskDefinitionArn], ++ actions: ['ecs:*'], ++ resources: ['*'], // full ecs + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/provenance.json new file mode 100644 index 00000000..ea2e70f1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/commits/provenance.json @@ -0,0 +1,182 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C10": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b5ed539", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C11": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "bc3a672", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C12": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "0cae334", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b248f61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "4b85402", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "e19e08d", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "ab2794b", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "67601b9", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "4adbbeb", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C9": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "a5238f4", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/metadata.yaml new file mode 100644 index 00000000..b4ea1dc8 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/metadata.yaml @@ -0,0 +1,168 @@ +benchmark: G3 +family: Privilege Drift +drift_name: Orchestrator ECS Wildcard +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The orchestrator's ECS grant adds Describe/Stop actions (C6, Mild), then becomes ecs:*\ + \ on '*' (C9, Severe) \u2014 it can manage any task/service, not just the sandbox." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'orchestrator ECS grant: RunTask on the task def -> ecs:* on ''*''.' +commit_count: 12 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: b248f61 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C4: + sha: 4b85402 + label: VB + message: 'chore: add api stage throttling' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: stage tuning + C5: + sha: e19e08d + label: VB + message: 'chore: raise lambda memory and timeout' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: perf tuning + C6: + sha: ab2794b + label: V2 + message: 'feat: let orchestrator track and stop execution tasks' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: G1 + operation: mutate + mechanism: ecs_action_broaden + path: Orchestrator -> ecs:Describe/Stop -> execution task def + controls_present: + - TaskDefScoped + controls_absent: [] + component: ExecutionOrchestratorRole + transitive_reach: + - manage the sandbox task lifecycle + construct_ids: + - ExecutionOrchestratorRole + template_assertion: ECS action list gains DescribeTasks + StopTask, resource unchanged + note: More actions, still scoped to the one task def. Mild. + C7: + sha: 67601b9 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C8: + sha: 4adbbeb + label: VB + message: 'chore: add known-bad-inputs waf rule' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: WAF hardening decoy + C9: + sha: a5238f4 + label: V3 + message: 'fix: grant full ecs to manage a second runner cluster' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: G1 + operation: mutate + mechanism: ecs_full_wildcard + path: Orchestrator -> ecs:* -> * (any task/service) + controls_present: [] + controls_removed: + - TaskDefScoped + component: ExecutionOrchestratorRole + transitive_reach: + - run/stop/manage any ECS workload + construct_ids: + - ExecutionOrchestratorRole + template_assertion: ECS statement becomes ecs:* on Resource '*' + note: The launcher can now run arbitrary tasks, not just the sandboxed definition. + C10: + sha: b5ed539 + label: VB + message: 'chore: add vpc id stack output' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: cosmetic output + C11: + sha: bc3a672 + label: VB + message: 'docs: add orchestration runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe + C12: + sha: 0cae334 + label: VB + message: 'chore: extend gitignore' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: zero template diff +baseline_known_weaknesses: +- orchestrator holds iam:PassRole at C1 +- RunTask launches untrusted code at C1 +scoring: + drift_commits: + - C6 + - C9 + benign_commits: + - C2 + - C3 + - C4 + - C5 + - C7 + - C8 + - C10 + - C11 + - C12 + false_positive_probes: + - C7 + - C8 + state_vs_event_probes: + - C10 + - C11 + - C12 + severity_axis: orchestrator ECS grant breadth (RunTask on task def -> ecs:*) + note: Action wildcard at Mild, action+resource wildcard at Severe on the code-launcher role. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/repository new file mode 160000 index 00000000..0cae3346 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/repository @@ -0,0 +1 @@ +Subproject commit 0cae3346215faa2883644bf90a506d2c97cd65fd diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/template_analysis.json new file mode 100644 index 00000000..ec36e369 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G3/template_analysis.json @@ -0,0 +1,546 @@ +{ + "benchmark": "G3", + "drift_name": "Orchestrator ECS Wildcard", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "b248f61", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "4b85402", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "e19e08d", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "ab2794b", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 6, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "67601b9", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "4adbbeb", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 18, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C9": { + "sha": "a5238f4", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 10, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionOrchestratorRoleDefaultPolicyD8862B68", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [ + "ExecutionOrchestratorRoleDefaultPolicyD8862B68:ecs:*" + ], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C10": { + "sha": "b5ed539", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionOrchestratorRoleDefaultPolicyD8862B68", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [ + "ExecutionOrchestratorRoleDefaultPolicyD8862B68:ecs:*" + ], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C11": { + "sha": "bc3a672", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionOrchestratorRoleDefaultPolicyD8862B68", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [ + "ExecutionOrchestratorRoleDefaultPolicyD8862B68:ecs:*" + ], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C12": { + "sha": "0cae334", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "ExecutionOrchestratorRoleDefaultPolicyD8862B68", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [ + "ExecutionOrchestratorRoleDefaultPolicyD8862B68:ecs:*" + ], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/README.md new file mode 100644 index 00000000..620f7d83 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/README.md @@ -0,0 +1,135 @@ +# G4 — Sandbox Task to Administrator + +**Family:** Privilege Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The untrusted-code Fargate task role is granted PowerUserAccess (C2, Mild), then AdministratorAccess (C3, Severe) — the sandbox runs code as admin. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Task role managed policy: none -> PowerUser -> Administrator. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `1599b79` | V2 | **Mild** | Mild | 73 | **14** | +| C3 | `ffd6704` | V3 | **Severe** | Severe | 73 | **2** | +| C4 | `fa396d6` | VB | None | Severe | 73 | 400 | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C4 at 400 lines**. +The smallest drift-bearing diff is **C3 at 2 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C2 — V2, Mild + +`feat: grant execution task poweruser for broader runners` + +- **Mechanism:** `task_managed_poweruser` +- **Path:** `ExecutionTaskRole -> PowerUserAccess` +- **Controls present:** NoIamActions +- **Component:** `ExecutionTaskDef.taskRole` +- **Transitive reach:** most services from untrusted code +- **Template assertion:** task role ManagedPolicyArns gains PowerUserAccess + +Very broad, but no IAM. Mild. + +### C3 — V3, Severe + +`fix: bump execution task to administrator to unblock a runner` + +- **Mechanism:** `task_managed_administrator` +- **Path:** `ExecutionTaskRole -> AdministratorAccess` +- **Controls present:** none +- **Controls removed:** NoIamActions +- **Component:** `ExecutionTaskDef.taskRole` +- **Transitive reach:** everything, from untrusted code +- **Template assertion:** ManagedPolicyArns PowerUserAccess -> AdministratorAccess + +Untrusted code as admin — the worst case for a sandbox. Two-word diff. + + +## Benign commits — why each is a probe + +- **C4** `chore: apply cost-allocation tags` — largest template diff + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- the task role runs untrusted user code at C1 +- no permissions boundary on the task role at C1 + +## Scoring + +- **Drift commits:** C2, C3 +- **Benign commits:** C4 +- **False-positive probes:** C4 + +- **State-vs-event probes:** + +Cross-suite Administrator pair; the blast radius is 'untrusted code runs as admin'. + +## Layout + +``` +G4/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark g4 --baseline /text-paste-service/v1/cdk --out G4 +python3 generators/synth.py --root G4 --workbench /tmp/wb +python3 generators/analyze.py --root G4 +python3 generators/verify.py --benchmark g4 --root G4 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/g4.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..3760bbb3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/cdk.ts @@ -0,0 +1,411 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + executionTaskDefinition.taskRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('PowerUserAccess')); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/commit.json new file mode 100644 index 00000000..9e927ad9 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "1599b79", + "full_sha": "1599b794be63214afcac067350d565d072811b3e", + "parent": "fe2cb61", + "message": "feat: grant execution task poweruser for broader runners", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/diff.patch new file mode 100644 index 00000000..da5adb03 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C2/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..3760bbb 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -106,6 +106,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + ++ executionTaskDefinition.taskRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('PowerUserAccess')); ++ + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..33d9bd06 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/cdk.ts @@ -0,0 +1,411 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + executionTaskDefinition.taskRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/commit.json new file mode 100644 index 00000000..3a6cac70 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "ffd6704", + "full_sha": "ffd6704d7d5b2bdffac540b0fa346cc081678949", + "parent": "1599b79", + "message": "fix: bump execution task to administrator to unblock a runner", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/diff.patch new file mode 100644 index 00000000..a49ac236 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 3760bbb..33d9bd0 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -106,7 +106,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + +- executionTaskDefinition.taskRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('PowerUserAccess')); ++ executionTaskDefinition.taskRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')); + + // === Lambda Functions === + const defaultLambdaProps = { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..059878af --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/cdk.ts @@ -0,0 +1,416 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + executionTaskDefinition.taskRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/commit.json new file mode 100644 index 00000000..584b761b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "fa396d6", + "full_sha": "fa396d684773dc8124faa6fcad6d641376bb3f52", + "parent": "ffd6704", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/diff.patch new file mode 100644 index 00000000..139c65e2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/C4/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 33d9bd0..059878a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/provenance.json new file mode 100644 index 00000000..2d807e82 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/commits/provenance.json @@ -0,0 +1,62 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "1599b79", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "ffd6704", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fa396d6", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/metadata.yaml new file mode 100644 index 00000000..207dffd3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/metadata.yaml @@ -0,0 +1,92 @@ +benchmark: G4 +family: Privilege Drift +drift_name: Sandbox Task to Administrator +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The untrusted-code Fargate task role is granted PowerUserAccess (C2, Mild), then AdministratorAccess\ + \ (C3, Severe) \u2014 the sandbox runs code as admin." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Task role managed policy: none -> PowerUser -> Administrator.' +commit_count: 4 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: 1599b79 + label: V2 + message: 'feat: grant execution task poweruser for broader runners' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: G1 + operation: add + mechanism: task_managed_poweruser + path: ExecutionTaskRole -> PowerUserAccess + controls_present: + - NoIamActions + controls_absent: [] + component: ExecutionTaskDef.taskRole + transitive_reach: + - most services from untrusted code + construct_ids: + - ExecutionTaskDef + template_assertion: task role ManagedPolicyArns gains PowerUserAccess + note: Very broad, but no IAM. Mild. + C3: + sha: ffd6704 + label: V3 + message: 'fix: bump execution task to administrator to unblock a runner' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: G1 + operation: mutate + mechanism: task_managed_administrator + path: ExecutionTaskRole -> AdministratorAccess + controls_present: [] + controls_removed: + - NoIamActions + component: ExecutionTaskDef.taskRole + transitive_reach: + - everything, from untrusted code + construct_ids: + - ExecutionTaskDef + template_assertion: ManagedPolicyArns PowerUserAccess -> AdministratorAccess + note: "Untrusted code as admin \u2014 the worst case for a sandbox. Two-word diff." + C4: + sha: fa396d6 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: largest template diff +baseline_known_weaknesses: +- the task role runs untrusted user code at C1 +- no permissions boundary on the task role at C1 +scoring: + drift_commits: + - C2 + - C3 + benign_commits: + - C4 + false_positive_probes: + - C4 + state_vs_event_probes: [] + severity_axis: task-role managed-policy breadth + note: Cross-suite Administrator pair; the blast radius is 'untrusted code runs as admin'. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/repository new file mode 160000 index 00000000..fa396d68 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/repository @@ -0,0 +1 @@ +Subproject commit fa396d684773dc8124faa6fcad6d641376bb3f52 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/template_analysis.json new file mode 100644 index 00000000..91ce4e16 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/G4/template_analysis.json @@ -0,0 +1,185 @@ +{ + "benchmark": "G4", + "drift_name": "Sandbox Task to Administrator", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "1599b79", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 14, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "PowerUserAccess", + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "ffd6704", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "AdministratorAccess", + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "fa396d6", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "AdministratorAccess", + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/PULL_REQUEST.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/PULL_REQUEST.md new file mode 100644 index 00000000..1446fa96 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/PULL_REQUEST.md @@ -0,0 +1,146 @@ +# CDK Drift Benchmark Suite — 18 benchmarks across 5 families + +## Summary + +Adds `benchmarks-codeexec/` — 18 independent parallel evolutions of the +`code-execution-platform` CDK stack, one per drift scenario. Every benchmark is a real git +repository with real commits (4 to 14 each, 4 minimum) and a per-commit synthesized +CloudFormation template. All 18 share commit C1 = `fe2cb61` byte-for-byte; divergence +starts at C2. + +Companion to the text-paste (25), containerized-microservices (30), support-ticketing (28), +Bedrock-chatbot (32), image-website (21) and security-response (18) suites. This baseline is +an **untrusted-code-execution sandbox**: a WAF-protected API Gateway feeds a five-Lambda +pipeline (apiHandler → requestValidator → executionOrchestrator → resultProcessor → +responseHandler) that launches an ECS Fargate task to run submitted code, with S3 +code/results buckets and a DynamoDB results table. + +**Total: 18 benchmarks, 151 commits, 45 MB, 100% verified and typechecked.** Seven suites +now total 25 + 30 + 28 + 32 + 21 + 18 + 18 = 172 benchmarks. + +## Sized to the architecture, not to a number + +The threat model is the sandbox boundary — the Fargate task that runs arbitrary user code, +the orchestrator that launches it, and the submitted-code bucket. So the honest drift shape +is **privilege- and reachability-heavy** with the code bucket as the crown-jewel exposure +asset; families are sized to the mechanisms that genuinely exist, with no padding. + +## Drift families + +Each family holds severity to a single axis; every benchmark labels exactly two commits — +V2 (Mild) and V3 (Severe) — with the rest benign. + +| Family | Axis | Benchmarks | +|---|---|---| +| **R — Architectural Reachability** | the sandbox network + reaching the executor | R1 task in public subnets, R2 orchestrator Function URL bypass, R3 /submit auth removed | +| **G — Privilege** | the sandbox role and the launcher | G1 task reads code→s3:*, G2 orchestrator PassRole→*, G3 orchestrator ecs:*, G4 task role→Administrator | +| **E — Exposure** | submitted-code store + the API's WAF | E1 code BlockPublicAccess, E2 code bucket policy, E3 code protections, E4 WAF removed | +| **D — Dependency / Integration** | third party in the code pipeline | D1 scanner fail-open, D2 package mirror unverified, D3 result webhook signature, D4 base-image registry | +| **T — Trust Boundary** | cross-account seams around the sandbox | T1 code bucket cross-account, T2 task role foreign trust, T3 VPC peering | + +Cross-family pairs are scoreable — **G4↔T2** (the same sandbox task role: permission +escalation vs trust widening), **G1** (untrusted code reads all code then any bucket), and +the S3 `BlockPublicAccess` drift **E1** is a **septuple-baseline oracle** across all seven +suites. + +## Commit log structure + +Every benchmark's `repository/` is a genuine git repo (R1 shown): + +``` +935634a chore: extend gitignore # VB benign +1c3692c docs: add networking runbook # VB benign +116bee1 chore: raise lambda memory and timeout # VB benign +e4d3ee1 fix: run execution tasks in public subnets to drop nat cost # V3 Severe (R1) +b81c9aa chore: apply cost-allocation tags # VB benign +72c5e3b feat: allow execution tasks to launch in public subnets # V2 Mild +b248f61 chore: extend code retention to two years # VB benign +afc6521 chore: add log level env to lambdas # VB benign +fe2cb61 feat: code execution platform baseline # V1 (shared) +``` + +Author, date and identity are pinned so SHAs are reproducible. Every benchmark's C1 is +`fe2cb61`; divergence starts at C2. + +Commit-count distribution (no drift-position collision within a length): + +``` +count: 4 5 6 7 8 9 10 11 12 13 14 +benchmark: E1 G4 D4 G2 E3 R2 D1 E2 G1 T1 R1 D2 T2 R3 D3 G3 E4 T3 +``` + +## Per-benchmark layout + +Each `benchmarks-codeexec//` mirrors the source dataset's `/cdk/` folder shape: + +``` +R1/ +├── repository/ # real working tree + real .git +├── commits/ +│ ├── C1..CN/ +│ │ ├── cdk/ # same layout as code-execution-platform/cdk/ +│ │ │ ├── cdk.ts, cdk.json, package.json, tsconfig.json +│ │ │ └── cdk.out/ # synthesized template, tree.json, manifests +│ │ ├── commit.json # sha, parent, author, label, severities, diffstat +│ │ └── diff.patch # diff against parent (empty for C1) +│ └── provenance.json # synth version and resource count per commit +├── metadata.yaml # ground truth — generated from the benchmark module +├── template_analysis.json # measured diffs and control state per commit +└── README.md # generated spec +``` + +Tooling written against `code-execution-platform/cdk/cdk.out/*.template.json` works against +`benchmarks-codeexec/R1/commits/C5/cdk/cdk.out/*.template.json` with only the root path +changed. Resource counts run 72 (baseline) → 75. + +## metadata.yaml — the answer key + +Deliberately outside `repository/` so it can't leak into anything a detector reads. Per +commit: `sha`, `label` (V1/V2/V3/VB), `commit_severity`, `cumulative_severity`, and for +drift commits a `ground_truth` block with mechanism, path, controls present/absent/removed, +transitive reach, and a `template_assertion` string. `commit_severity` is the drift +introduced by that commit; `cumulative_severity` is the standing risk at that commit. + +## Suite property worth naming + +Template diff size is deliberately anti-correlated with severity. Benign cost-allocation +tag commits produce the largest diff (~400 lines); severe commits flip one or a few fields: + +| | Severe | benign (biggest) | +|---|---|---| +| T3 | 2 lines (peering route → 0.0.0.0/0) | 412 lines | +| G4 | 2 lines (task role → Administrator) | 400 lines | +| E1 | 4 lines (BlockPublicAccess all-false) | 400 lines | +| G1 | 5 lines (task role s3:* on '*') | 400 lines | +| R3 | 6 lines (apiKeyRequired → false) | 400 lines | +| D1–D4 | 10 lines (integration flag flip across the shared env) | 400 lines | + +Any detector triaging by diff magnitude scores worse than chance. + +## Septuple-baseline oracle (free ground truth) + +The source dataset's code bucket uses `BlockPublicAccess.BLOCK_ALL`; **E1** drifts it to +all-false — the same mechanism as the E-family in all six prior suites. Detector +performance on synthetic vs. real curated drift for one mechanism is now comparable across +**seven** different stacks. + +## Known limitation + +The baseline ships no `package.json` at the cdk root, so no `aws-cdk-lib` version is +declared; all templates were synthesized with 2.150.0 and commits flag `version_match: +false` in `provenance.json` (declaring the 2.100.0 default supplied at import). Within a +benchmark every template comes from one library version, so cross-commit diffs are clean. +One tsc-only normalization is applied: `logs.RetentionDays.SEVEN_DAYS` does not exist in +2.150.0 and is replaced with `ONE_WEEK` (both 7 days). Because raw `ts-node` synth does not +read `cdk.json`, the required context (VPC/Fargate sizing, bucket/table names, and the +WAF/Shield/SecurityHub feature flags) is injected via `synth_context.json`; WAF is enabled +so the WebACL exists at C1. + +## Not included + +`threat-model.json`, `canonical_ir.json`, the `7.*` graph IRs, `architecture.png` and +`diagram.py` from the source dataset are absent — they come from tooling outside this +generator. A stale threat model copied forward would falsely assert "nothing changed" at +exactly the commits where the sandbox role turns admin or the executor becomes publicly +reachable, which is worse than having none. Run your own pipeline over `commits/C*/cdk/` to +produce them. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/README.md new file mode 100644 index 00000000..c0b621f3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/README.md @@ -0,0 +1,150 @@ +# R1 — Execution Task in Public Subnets + +**Family:** Architectural Reachability Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The execution-task subnet list adds public subnets (C4, Mild), then becomes public only (C6, Severe) — the untrusted-code Fargate task gets a public IP and direct internet reachability. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Fargate execution subnets: private -> private+public -> public only. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `b248f61` | VB | None | None | 73 | 2 | +| C4 | `72c5e3b` | V2 | **Mild** | Mild | 73 | **40** | +| C5 | `b81c9aa` | VB | None | Mild | 73 | 400 | +| C6 | `e4d3ee1` | V3 | **Severe** | Severe | 73 | **40** | +| C7 | `116bee1` | VB | None | Severe | 73 | 20 | +| C8 | `1c3692c` | VB | None | Severe | 73 | **0** | +| C9 | `935634a` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C5 at 400 lines**. +The smallest drift-bearing diff is **C4 at 40 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | +| C9 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C4 — V2, Mild + +`feat: allow execution tasks to launch in public subnets` + +- **Mechanism:** `exec_task_mixed_subnets` +- **Path:** `Fargate exec task -> private+public subnets` +- **Controls present:** PrivateSubnetOption +- **Component:** `ExecutionOrchestratorLambda` +- **Transitive reach:** task may get a public IP +- **Template assertion:** orchestrator env subnet list includes public subnet ids + +Public placement possible, private still available. Mild. + +### C6 — V3, Severe + +`fix: run execution tasks in public subnets to drop nat cost` + +- **Mechanism:** `exec_task_public_only` +- **Path:** `internet <-> Fargate exec task (public IP)` +- **Controls present:** none +- **Controls removed:** PrivateSubnetOption +- **Component:** `ExecutionOrchestratorLambda` +- **Transitive reach:** untrusted code has direct internet ingress/egress +- **Template assertion:** orchestrator env subnet list contains only public subnet ids + +The untrusted-code container runs on a public IP; sandbox network boundary gone. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C3** `chore: extend code retention to two years` — retention only +- **C5** `chore: apply cost-allocation tags` — largest template diff +- **C7** `chore: raise lambda memory and timeout` — perf tuning +- **C8** `docs: add networking runbook` — no template change while cumulative Severe +- **C9** `chore: extend gitignore` — zero template diff + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- the Fargate task runs untrusted user code at C1 +- single NAT gateway egress at C1 + +## Scoring + +- **Drift commits:** C4, C6 +- **Benign commits:** C2, C3, C5, C7, C8, C9 +- **False-positive probes:** C5 + +- **State-vs-event probes:** C8, C9 + +Sandbox network exposure; the untrusted container becomes internet-reachable. + +## Layout + +``` +R1/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark r1 --baseline /text-paste-service/v1/cdk --out R1 +python3 generators/synth.py --root R1 --workbench /tmp/wb +python3 generators/analyze.py --root R1 +python3 generators/verify.py --benchmark r1 --root R1 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/r1.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5, C6, C7, C8, C9 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..98b6e0ad --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/commit.json new file mode 100644 index 00000000..e2720449 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "b248f61", + "full_sha": "b248f61f7206d4b474f7a0405a873dcc9b68dc27", + "parent": "afc6521", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/diff.patch new file mode 100644 index 00000000..980baa5e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..98b6e0a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..d96efa47 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify([...vpc.privateSubnets, ...vpc.publicSubnets].map(subnet => subnet.subnetId)), // added public subnets + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/commit.json new file mode 100644 index 00000000..60cd0a25 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "72c5e3b", + "full_sha": "72c5e3bede3f492168c2232871ddd12f204e633b", + "parent": "b248f61", + "message": "feat: allow execution tasks to launch in public subnets", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/diff.patch new file mode 100644 index 00000000..9cf69dfd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C4/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 98b6e0a..d96efa4 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -120,7 +120,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, +- VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), ++ VPC_PRIVATE_SUBNET_IDS: JSON.stringify([...vpc.privateSubnets, ...vpc.publicSubnets].map(subnet => subnet.subnetId)), // added public subnets + }, + }; \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..2d1cfe51 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify([...vpc.privateSubnets, ...vpc.publicSubnets].map(subnet => subnet.subnetId)), // added public subnets + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/commit.json new file mode 100644 index 00000000..56226e2f --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "b81c9aa", + "full_sha": "b81c9aa527a0cce02ce634aeec5b6af35cfffc8c", + "parent": "72c5e3b", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/diff.patch new file mode 100644 index 00000000..6dc248f1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C5/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index d96efa4..2d1cfe5 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..3b69c816 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.publicSubnets.map(subnet => subnet.subnetId)), // public subnets only + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/commit.json new file mode 100644 index 00000000..de30215d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "e4d3ee1", + "full_sha": "e4d3ee11f07bf0e1ab7e36e7102d4e19996bcdf7", + "parent": "b81c9aa", + "message": "fix: run execution tasks in public subnets to drop nat cost", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/diff.patch new file mode 100644 index 00000000..78d0e94b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C6/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 2d1cfe5..3b69c81 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -125,7 +125,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, +- VPC_PRIVATE_SUBNET_IDS: JSON.stringify([...vpc.privateSubnets, ...vpc.publicSubnets].map(subnet => subnet.subnetId)), // added public subnets ++ VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.publicSubnets.map(subnet => subnet.subnetId)), // public subnets only + }, + }; \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..f32103bb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.publicSubnets.map(subnet => subnet.subnetId)), // public subnets only + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/commit.json new file mode 100644 index 00000000..0d969f73 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "116bee1", + "full_sha": "116bee14a9780070d32fa8bc032f9d654c04089c", + "parent": "e4d3ee1", + "message": "chore: raise lambda memory and timeout", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/diff.patch new file mode 100644 index 00000000..1cb72b01 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C7/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index 3b69c81..f32103b 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -115,8 +115,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name +- memorySize: 256, +- timeout: cdk.Duration.seconds(30), ++ memorySize: 512, ++ timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..f32103bb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.publicSubnets.map(subnet => subnet.subnetId)), // public subnets only + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/commit.json new file mode 100644 index 00000000..9c5f83bb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "1c3692c", + "full_sha": "1c3692caf962070f47d4e33f6b41f0eacd3f5b98", + "parent": "116bee1", + "message": "docs: add networking runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C8/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/cdk.ts new file mode 100644 index 00000000..f32103bb --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/cdk.ts @@ -0,0 +1,415 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.publicSubnets.map(subnet => subnet.subnetId)), // public subnets only + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/commit.json new file mode 100644 index 00000000..4cb67738 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C9", + "sha": "935634a", + "full_sha": "935634a41c2b57e47e886c019fe465223cde4073", + "parent": "1c3692c", + "message": "chore: extend gitignore", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-29T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + ".gitignore" + ], + "diffstat": ".gitignore | 3 +++\n 1 file changed, 3 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/diff.patch new file mode 100644 index 00000000..81ec2928 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/C9/diff.patch @@ -0,0 +1,11 @@ +diff --git a/.gitignore b/.gitignore +index a3dd4ae..a4c0727 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,6 @@ + node_modules/ + cdk.out/ + *.log ++.DS_Store ++coverage/ ++*.tsbuildinfo \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/provenance.json new file mode 100644 index 00000000..5315faf5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/commits/provenance.json @@ -0,0 +1,137 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b248f61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "72c5e3b", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b81c9aa", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "e4d3ee1", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "116bee1", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "1c3692c", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C9": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "935634a", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/metadata.yaml new file mode 100644 index 00000000..0073d3e0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/metadata.yaml @@ -0,0 +1,140 @@ +benchmark: R1 +family: Architectural Reachability Drift +drift_name: Execution Task in Public Subnets +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The execution-task subnet list adds public subnets (C4, Mild), then becomes public\ + \ only (C6, Severe) \u2014 the untrusted-code Fargate task gets a public IP and direct internet\ + \ reachability." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Fargate execution subnets: private -> private+public -> public only.' +commit_count: 9 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: b248f61 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C4: + sha: 72c5e3b + label: V2 + message: 'feat: allow execution tasks to launch in public subnets' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: R1 + operation: mutate + mechanism: exec_task_mixed_subnets + path: Fargate exec task -> private+public subnets + controls_present: + - PrivateSubnetOption + controls_absent: [] + component: ExecutionOrchestratorLambda + transitive_reach: + - task may get a public IP + construct_ids: + - ExecutionOrchestratorLambda + template_assertion: orchestrator env subnet list includes public subnet ids + note: Public placement possible, private still available. Mild. + C5: + sha: b81c9aa + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C6: + sha: e4d3ee1 + label: V3 + message: 'fix: run execution tasks in public subnets to drop nat cost' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: R1 + operation: mutate + mechanism: exec_task_public_only + path: internet <-> Fargate exec task (public IP) + controls_present: [] + controls_removed: + - PrivateSubnetOption + component: ExecutionOrchestratorLambda + transitive_reach: + - untrusted code has direct internet ingress/egress + construct_ids: + - ExecutionOrchestratorLambda + template_assertion: orchestrator env subnet list contains only public subnet ids + note: The untrusted-code container runs on a public IP; sandbox network boundary gone. + C7: + sha: 116bee1 + label: VB + message: 'chore: raise lambda memory and timeout' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: perf tuning + C8: + sha: 1c3692c + label: VB + message: 'docs: add networking runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe + C9: + sha: 935634a + label: VB + message: 'chore: extend gitignore' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: zero template diff +baseline_known_weaknesses: +- the Fargate task runs untrusted user code at C1 +- single NAT gateway egress at C1 +scoring: + drift_commits: + - C4 + - C6 + benign_commits: + - C2 + - C3 + - C5 + - C7 + - C8 + - C9 + false_positive_probes: + - C5 + state_vs_event_probes: + - C8 + - C9 + severity_axis: execution-task subnet placement (private -> public) + note: Sandbox network exposure; the untrusted container becomes internet-reachable. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/repository new file mode 160000 index 00000000..935634a4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/repository @@ -0,0 +1 @@ +Subproject commit 935634a41c2b57e47e886c019fe465223cde4073 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/template_analysis.json new file mode 100644 index 00000000..fa6a53ff --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R1/template_analysis.json @@ -0,0 +1,402 @@ +{ + "benchmark": "R1", + "drift_name": "Execution Task in Public Subnets", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "b248f61", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "72c5e3b", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 40, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "b81c9aa", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "e4d3ee1", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 40, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "116bee1", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "1c3692c", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C9": { + "sha": "935634a", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/README.md new file mode 100644 index 00000000..d2b74c08 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/README.md @@ -0,0 +1,141 @@ +# R2 — Orchestrator Function URL Bypass + +**Family:** Architectural Reachability Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The ExecutionOrchestrator Lambda gets a Function URL, IAM-authenticated (C3, Mild) then unauthenticated (C5, Severe) — direct invoke of the code-launcher, bypassing the API, WAF and validator. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +ExecutionOrchestrator Function URL auth: none -> AWS_IAM -> NONE. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `a14e0c3` | V2 | **Mild** | Mild | 74 | **26** | +| C4 | `e826671` | VB | None | Mild | 74 | 400 | +| C5 | `3cd87bb` | V3 | **Severe** | Severe | 75 | **22** | +| C6 | `af36625` | VB | None | Severe | 75 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C4 at 400 lines**. +The smallest drift-bearing diff is **C5 at 22 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | Lambda URL auth=AWS_IAM | +| C4 | 0/2 | 0 | Lambda URL auth=AWS_IAM | +| C5 | 0/2 | 0 | Lambda URL auth=NONE, **public invoke permission** | +| C6 | 0/2 | 0 | Lambda URL auth=NONE, **public invoke permission** | + +## Drift commits — ground truth + +### C3 — V2, Mild + +`feat: add iam-authed function url for the orchestrator` + +- **Mechanism:** `lambda_function_url_iam` +- **Path:** `SigV4 caller -> Function URL -> ExecutionOrchestratorLambda` +- **Controls present:** AwsIamAuth +- **Component:** `ExecutionOrchestratorLambda` +- **Transitive reach:** launch executions, for authed callers +- **Template assertion:** AWS::Lambda::Url with AuthType AWS_IAM + +Bypass path added, still IAM-gated. Mild. + +### C5 — V3, Severe + +`fix: drop auth on orchestrator url for the partner runner` + +- **Mechanism:** `lambda_function_url_public` +- **Path:** `internet -> Function URL (no auth) -> ExecutionOrchestratorLambda` +- **Controls present:** none +- **Controls removed:** AwsIamAuth, ApiWafValidator +- **Component:** `ExecutionOrchestratorLambda` +- **Transitive reach:** anyone can launch untrusted-code executions +- **Template assertion:** AWS::Lambda::Url AuthType flips AWS_IAM -> NONE + +Unauthenticated invoke of the code-launcher; the whole API/WAF/validator chain is skipped. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C4** `chore: apply cost-allocation tags` — largest template diff +- **C6** `docs: add orchestration runbook` — no template change while cumulative Severe + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- orchestrator has ecs:RunTask + iam:PassRole at C1 +- the API path enforces WAF + a validator lambda at C1 + +## Scoring + +- **Drift commits:** C3, C5 +- **Benign commits:** C2, C4, C6 +- **False-positive probes:** C4 + +- **State-vs-event probes:** C6 + +Direct-invoke reachability of the code-launcher, bypassing the API/WAF/validator chain. + +## Layout + +``` +R2/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark r2 --baseline /text-paste-service/v1/cdk --out R2 +python3 generators/synth.py --root R2 --workbench /tmp/wb +python3 generators/analyze.py --root R2 +python3 generators/verify.py --benchmark r2 --root R2 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/r2.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5, C6 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..958d1e09 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/cdk.ts @@ -0,0 +1,416 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // Direct invocation entry point for internal tooling + const orchestratorUrl = executionOrchestratorLambda.addFunctionUrl({ + authType: lambda.FunctionUrlAuthType.AWS_IAM, + }); + new cdk.CfnOutput(this, 'OrchestratorUrlOutput', { value: orchestratorUrl.url }); + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/commit.json new file mode 100644 index 00000000..36720099 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "a14e0c3", + "full_sha": "a14e0c3d99d9c99a442f7f0a61cd8e018fa53cd7", + "parent": "afc6521", + "message": "feat: add iam-authed function url for the orchestrator", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 6 ++++++\n 1 file changed, 6 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/diff.patch new file mode 100644 index 00000000..ec63f581 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C3/diff.patch @@ -0,0 +1,17 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..958d1e0 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -355,6 +355,12 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + }); + } + ++ // Direct invocation entry point for internal tooling ++ const orchestratorUrl = executionOrchestratorLambda.addFunctionUrl({ ++ authType: lambda.FunctionUrlAuthType.AWS_IAM, ++ }); ++ new cdk.CfnOutput(this, 'OrchestratorUrlOutput', { value: orchestratorUrl.url }); ++ + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..9c4ccb73 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/cdk.ts @@ -0,0 +1,421 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // Direct invocation entry point for internal tooling + const orchestratorUrl = executionOrchestratorLambda.addFunctionUrl({ + authType: lambda.FunctionUrlAuthType.AWS_IAM, + }); + new cdk.CfnOutput(this, 'OrchestratorUrlOutput', { value: orchestratorUrl.url }); + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/commit.json new file mode 100644 index 00000000..0d26a413 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "e826671", + "full_sha": "e82667186a68e81f1693b518957eafe6ec508d67", + "parent": "a14e0c3", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/diff.patch new file mode 100644 index 00000000..df2acc04 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C4/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 958d1e0..9c4ccb7 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..84b1a955 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/cdk.ts @@ -0,0 +1,421 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // Direct invocation entry point for internal tooling + const orchestratorUrl = executionOrchestratorLambda.addFunctionUrl({ + authType: lambda.FunctionUrlAuthType.NONE, + }); + new cdk.CfnOutput(this, 'OrchestratorUrlOutput', { value: orchestratorUrl.url }); + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/commit.json new file mode 100644 index 00000000..864c2090 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "3cd87bb", + "full_sha": "3cd87bb062bc9c33cd9db08fb0a75c2dfddb7a9a", + "parent": "e826671", + "message": "fix: drop auth on orchestrator url for the partner runner", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/diff.patch new file mode 100644 index 00000000..285c8a9c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C5/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 9c4ccb7..84b1a95 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -362,7 +362,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + + // Direct invocation entry point for internal tooling + const orchestratorUrl = executionOrchestratorLambda.addFunctionUrl({ +- authType: lambda.FunctionUrlAuthType.AWS_IAM, ++ authType: lambda.FunctionUrlAuthType.NONE, + }); + new cdk.CfnOutput(this, 'OrchestratorUrlOutput', { value: orchestratorUrl.url }); \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..84b1a955 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/cdk.ts @@ -0,0 +1,421 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // Direct invocation entry point for internal tooling + const orchestratorUrl = executionOrchestratorLambda.addFunctionUrl({ + authType: lambda.FunctionUrlAuthType.NONE, + }); + new cdk.CfnOutput(this, 'OrchestratorUrlOutput', { value: orchestratorUrl.url }); + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/commit.json new file mode 100644 index 00000000..1a4231c4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "af36625", + "full_sha": "af36625469d2e203e4ae279cb812b237450539f9", + "parent": "3cd87bb", + "message": "docs: add orchestration runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/C6/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/provenance.json new file mode 100644 index 00000000..8ddca953 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/commits/provenance.json @@ -0,0 +1,92 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "a14e0c3", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "e826671", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "3cd87bb", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "af36625", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/metadata.yaml new file mode 100644 index 00000000..c901b06e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/metadata.yaml @@ -0,0 +1,113 @@ +benchmark: R2 +family: Architectural Reachability Drift +drift_name: Orchestrator Function URL Bypass +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The ExecutionOrchestrator Lambda gets a Function URL, IAM-authenticated (C3, Mild)\ + \ then unauthenticated (C5, Severe) \u2014 direct invoke of the code-launcher, bypassing the API,\ + \ WAF and validator." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'ExecutionOrchestrator Function URL auth: none -> AWS_IAM -> NONE.' +commit_count: 6 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: a14e0c3 + label: V2 + message: 'feat: add iam-authed function url for the orchestrator' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: R1 + operation: add + mechanism: lambda_function_url_iam + path: SigV4 caller -> Function URL -> ExecutionOrchestratorLambda + controls_present: + - AwsIamAuth + controls_absent: [] + component: ExecutionOrchestratorLambda + transitive_reach: + - launch executions, for authed callers + construct_ids: + - ExecutionOrchestratorLambda + template_assertion: AWS::Lambda::Url with AuthType AWS_IAM + note: Bypass path added, still IAM-gated. Mild. + C4: + sha: e826671 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C5: + sha: 3cd87bb + label: V3 + message: 'fix: drop auth on orchestrator url for the partner runner' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: R1 + operation: mutate + mechanism: lambda_function_url_public + path: internet -> Function URL (no auth) -> ExecutionOrchestratorLambda + controls_present: [] + controls_removed: + - AwsIamAuth + - ApiWafValidator + component: ExecutionOrchestratorLambda + transitive_reach: + - anyone can launch untrusted-code executions + construct_ids: + - ExecutionOrchestratorLambda + template_assertion: AWS::Lambda::Url AuthType flips AWS_IAM -> NONE + note: Unauthenticated invoke of the code-launcher; the whole API/WAF/validator chain is skipped. + C6: + sha: af36625 + label: VB + message: 'docs: add orchestration runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe +baseline_known_weaknesses: +- orchestrator has ecs:RunTask + iam:PassRole at C1 +- the API path enforces WAF + a validator lambda at C1 +scoring: + drift_commits: + - C3 + - C5 + benign_commits: + - C2 + - C4 + - C6 + false_positive_probes: + - C4 + state_vs_event_probes: + - C6 + severity_axis: Function URL auth type on the orchestrator Lambda + note: Direct-invoke reachability of the code-launcher, bypassing the API/WAF/validator chain. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/repository new file mode 160000 index 00000000..af366254 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/repository @@ -0,0 +1 @@ +Subproject commit af36625469d2e203e4ae279cb812b237450539f9 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/template_analysis.json new file mode 100644 index 00000000..abca1964 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R2/template_analysis.json @@ -0,0 +1,282 @@ +{ + "benchmark": "R2", + "drift_name": "Orchestrator Function URL Bypass", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "a14e0c3", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 74, + "template_diff_lines": 26, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": { + "ExecutionOrchestratorLambdaFunctionUrl9419B1E8": "AWS_IAM" + }, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "e826671", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 74, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": { + "ExecutionOrchestratorLambdaFunctionUrl9419B1E8": "AWS_IAM" + }, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "3cd87bb", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 75, + "template_diff_lines": 22, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": { + "ExecutionOrchestratorLambdaFunctionUrl9419B1E8": "NONE" + }, + "public_url_permissions": [ + "ExecutionOrchestratorLambdainvokefunctionurl998666D4" + ], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "af36625", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 75, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": { + "ExecutionOrchestratorLambdaFunctionUrl9419B1E8": "NONE" + }, + "public_url_permissions": [ + "ExecutionOrchestratorLambdainvokefunctionurl998666D4" + ], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/README.md new file mode 100644 index 00000000..50f51aec --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/README.md @@ -0,0 +1,156 @@ +# R3 — Submit Endpoint Auth Removed + +**Family:** Architectural Reachability Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The /submit method requires an API key (C5, Mild), then the requirement is removed (C8, Severe) — the code-submission endpoint is fully open again. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +/submit method auth: none -> apiKeyRequired -> open. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `b248f61` | VB | None | None | 73 | 2 | +| C4 | `4b85402` | VB | None | None | 73 | 4 | +| C5 | `f23986d` | V2 | **Mild** | Mild | 73 | **5** | +| C6 | `113b6df` | VB | None | Mild | 73 | 400 | +| C7 | `3d5aa16` | VB | None | Mild | 73 | 18 | +| C8 | `11b8151` | V3 | **Severe** | Severe | 73 | **6** | +| C9 | `c34cf41` | VB | None | Severe | 73 | 20 | +| C10 | `bf5549a` | VB | None | Severe | 73 | 5 | +| C11 | `f3a167f` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C6 at 400 lines**. +The smallest drift-bearing diff is **C5 at 5 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | +| C9 | 0/2 | 0 | — | +| C10 | 0/2 | 0 | — | +| C11 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C5 — V2, Mild + +`feat: require an api key on the submit endpoint` + +- **Mechanism:** `submit_api_key` +- **Path:** `client -> (api key) -> /submit -> apiHandler` +- **Controls present:** ApiKeyRequired +- **Component:** `CodeExecutionApi` +- **Transitive reach:** submissions require a key +- **Template assertion:** submit POST method ApiKeyRequired true + +A weak but real gate on the open endpoint. Mild. + +### C8 — V3, Severe + +`fix: drop api key on submit for the public playground` + +- **Mechanism:** `submit_public` +- **Path:** `anyone -> /submit -> apiHandler -> execution` +- **Controls present:** none +- **Controls removed:** ApiKeyRequired +- **Component:** `CodeExecutionApi` +- **Transitive reach:** anyone can submit code to execute +- **Template assertion:** submit POST method ApiKeyRequired true -> false + +Code-submission endpoint fully open again. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C3** `chore: extend code retention to two years` — retention only +- **C4** `chore: add api stage throttling` — stage tuning +- **C6** `chore: apply cost-allocation tags` — largest template diff +- **C7** `chore: add known-bad-inputs waf rule` — WAF hardening decoy +- **C9** `chore: raise lambda memory and timeout` — perf tuning +- **C10** `chore: add vpc id stack output` — cosmetic output +- **C11** `docs: add api runbook` — no template change while cumulative Severe + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- /submit has no authorizer at C1 (WAF only) +- submissions run untrusted code at C1 + +## Scoring + +- **Drift commits:** C5, C8 +- **Benign commits:** C2, C3, C4, C6, C7, C9, C10, C11 +- **False-positive probes:** C6, C7 + +- **State-vs-event probes:** C10, C11 + +Gains then loses a submission gate; the endpoint feeds untrusted-code execution. + +## Layout + +``` +R3/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark r3 --baseline /text-paste-service/v1/cdk --out R3 +python3 generators/synth.py --root R3 --workbench /tmp/wb +python3 generators/analyze.py --root R3 +python3 generators/verify.py --benchmark r3 --root R3 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/r3.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C10, C11, C2, C3, C4, C5, C6, C7, C8, C9 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/cdk.ts new file mode 100644 index 00000000..6e5839a6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/cdk.ts @@ -0,0 +1,434 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + apiKeyRequired: false, // public submit + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/commit.json new file mode 100644 index 00000000..67df2110 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C10", + "sha": "bf5549a", + "full_sha": "bf5549a5056fcb71817e06939c874801fbcf428e", + "parent": "c34cf41", + "message": "chore: add vpc id stack output", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-06T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/diff.patch new file mode 100644 index 00000000..0bb8fa5a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C10/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 2c224cf..6e5839a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -379,6 +379,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + } + + // === Outputs === ++ new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/cdk.ts new file mode 100644 index 00000000..6e5839a6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/cdk.ts @@ -0,0 +1,434 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + apiKeyRequired: false, // public submit + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/commit.json new file mode 100644 index 00000000..191c0035 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C11", + "sha": "f3a167f", + "full_sha": "f3a167fd57f0b0823453b0bca82fc4dd3e530490", + "parent": "bf5549a", + "message": "docs: add api runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-13T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C11/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..98b6e0ad --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/commit.json new file mode 100644 index 00000000..e2720449 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "b248f61", + "full_sha": "b248f61f7206d4b474f7a0405a873dcc9b68dc27", + "parent": "afc6521", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/diff.patch new file mode 100644 index 00000000..980baa5e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..98b6e0a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..4810c003 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/commit.json new file mode 100644 index 00000000..f6f933be --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "4b85402", + "full_sha": "4b854020383bdba31e05781eef6a627e3b590ae5", + "parent": "b248f61", + "message": "chore: add api stage throttling", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/diff.patch new file mode 100644 index 00000000..d8433df4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 98b6e0a..4810c00 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -264,6 +264,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, ++ throttlingRateLimit: 100, ++ throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..22fc579f --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + apiKeyRequired: true, // require api key + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/commit.json new file mode 100644 index 00000000..2b7d1c07 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "f23986d", + "full_sha": "f23986d63d21335cec625894b2ebea469aec20fd", + "parent": "4b85402", + "message": "feat: require an api key on the submit endpoint", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/diff.patch new file mode 100644 index 00000000..eb7cee58 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C5/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 4810c00..22fc579 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -277,7 +277,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { +- // Add authorizer or API key requirements if needed ++ apiKeyRequired: true, // require api key + }); + + // Example: GET /results/{executionId} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..efa5b5c4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/cdk.ts @@ -0,0 +1,417 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + apiKeyRequired: true, // require api key + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/commit.json new file mode 100644 index 00000000..c4fb252e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "113b6df", + "full_sha": "113b6df68414cec40c137cd7dd0861e3488c3955", + "parent": "f23986d", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/diff.patch new file mode 100644 index 00000000..2f6cf592 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C6/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 22fc579..efa5b5c 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..f1e08dc4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/cdk.ts @@ -0,0 +1,433 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + apiKeyRequired: true, // require api key + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/commit.json new file mode 100644 index 00000000..37cbe109 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "3d5aa16", + "full_sha": "3d5aa16c6a73decc329869c30c23b87d7b3904e5", + "parent": "113b6df", + "message": "chore: add known-bad-inputs waf rule", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/diff.patch new file mode 100644 index 00000000..52873229 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C7/diff.patch @@ -0,0 +1,27 @@ +diff --git a/cdk.ts b/cdk.ts +index efa5b5c..f1e08dc 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -317,6 +317,22 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, ++ }, ++ { ++ name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', ++ priority: 2, ++ statement: { ++ managedRuleGroupStatement: { ++ vendorName: 'AWS', ++ name: 'AWSManagedRulesKnownBadInputsRuleSet', ++ }, ++ }, ++ overrideAction: { none: {} }, ++ visibilityConfig: { ++ cloudWatchMetricsEnabled: true, ++ metricName: 'KnownBadInputsMetric', ++ sampledRequestsEnabled: true, ++ }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..d3d66793 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/cdk.ts @@ -0,0 +1,433 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + apiKeyRequired: false, // public submit + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/commit.json new file mode 100644 index 00000000..077448a0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "11b8151", + "full_sha": "11b8151bde90f58b9a24eb2c76273cc0b0434d16", + "parent": "3d5aa16", + "message": "fix: drop api key on submit for the public playground", + "author": { + "name": "Dan Osei", + "email": "dan.osei@example.com", + "role": "product" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/diff.patch new file mode 100644 index 00000000..897e3882 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C8/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index f1e08dc..d3d6679 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -282,7 +282,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { +- apiKeyRequired: true, // require api key ++ apiKeyRequired: false, // public submit + }); + + // Example: GET /results/{executionId} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/cdk.ts new file mode 100644 index 00000000..2c224cff --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/cdk.ts @@ -0,0 +1,433 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + apiKeyRequired: false, // public submit + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/commit.json new file mode 100644 index 00000000..e5da0c26 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C9", + "sha": "c34cf41", + "full_sha": "c34cf41ca388fa63aec92e23eb439151a560cb85", + "parent": "11b8151", + "message": "chore: raise lambda memory and timeout", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-29T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/diff.patch new file mode 100644 index 00000000..76a954ed --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/C9/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index d3d6679..2c224cf 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -115,8 +115,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name +- memorySize: 256, +- timeout: cdk.Duration.seconds(30), ++ memorySize: 512, ++ timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/provenance.json new file mode 100644 index 00000000..7ef43340 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/commits/provenance.json @@ -0,0 +1,167 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C10": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "bf5549a", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C11": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "f3a167f", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b248f61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "4b85402", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "f23986d", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "113b6df", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "3d5aa16", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "11b8151", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C9": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "c34cf41", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/metadata.yaml new file mode 100644 index 00000000..d5a5d206 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/metadata.yaml @@ -0,0 +1,158 @@ +benchmark: R3 +family: Architectural Reachability Drift +drift_name: Submit Endpoint Auth Removed +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The /submit method requires an API key (C5, Mild), then the requirement is removed\ + \ (C8, Severe) \u2014 the code-submission endpoint is fully open again." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: '/submit method auth: none -> apiKeyRequired -> open.' +commit_count: 11 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: b248f61 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C4: + sha: 4b85402 + label: VB + message: 'chore: add api stage throttling' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: stage tuning + C5: + sha: f23986d + label: V2 + message: 'feat: require an api key on the submit endpoint' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: R1 + operation: add + mechanism: submit_api_key + path: client -> (api key) -> /submit -> apiHandler + controls_present: + - ApiKeyRequired + controls_absent: [] + component: CodeExecutionApi + transitive_reach: + - submissions require a key + construct_ids: + - CodeExecutionApi + template_assertion: submit POST method ApiKeyRequired true + note: A weak but real gate on the open endpoint. Mild. + C6: + sha: 113b6df + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C7: + sha: 3d5aa16 + label: VB + message: 'chore: add known-bad-inputs waf rule' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: WAF hardening decoy + C8: + sha: 11b8151 + label: V3 + message: 'fix: drop api key on submit for the public playground' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: R1 + operation: mutate + mechanism: submit_public + path: anyone -> /submit -> apiHandler -> execution + controls_present: [] + controls_removed: + - ApiKeyRequired + component: CodeExecutionApi + transitive_reach: + - anyone can submit code to execute + construct_ids: + - CodeExecutionApi + template_assertion: submit POST method ApiKeyRequired true -> false + note: Code-submission endpoint fully open again. + C9: + sha: c34cf41 + label: VB + message: 'chore: raise lambda memory and timeout' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: perf tuning + C10: + sha: bf5549a + label: VB + message: 'chore: add vpc id stack output' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: cosmetic output + C11: + sha: f3a167f + label: VB + message: 'docs: add api runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe +baseline_known_weaknesses: +- /submit has no authorizer at C1 (WAF only) +- submissions run untrusted code at C1 +scoring: + drift_commits: + - C5 + - C8 + benign_commits: + - C2 + - C3 + - C4 + - C6 + - C7 + - C9 + - C10 + - C11 + false_positive_probes: + - C6 + - C7 + state_vs_event_probes: + - C10 + - C11 + severity_axis: /submit method authentication (key required vs open) + note: Gains then loses a submission gate; the endpoint feeds untrusted-code execution. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/repository new file mode 160000 index 00000000..f3a167fd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/repository @@ -0,0 +1 @@ +Subproject commit f3a167fd57f0b0823453b0bca82fc4dd3e530490 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/template_analysis.json new file mode 100644 index 00000000..5cbda071 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/R3/template_analysis.json @@ -0,0 +1,490 @@ +{ + "benchmark": "R3", + "drift_name": "Submit Endpoint Auth Removed", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "b248f61", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "4b85402", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "f23986d", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "113b6df", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "3d5aa16", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 18, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "11b8151", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 6, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C9": { + "sha": "c34cf41", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C10": { + "sha": "bf5549a", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C11": { + "sha": "f3a167f", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/README.md new file mode 100644 index 00000000..1963e47b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/README.md @@ -0,0 +1,132 @@ +# Drift Benchmark Suite — `code-execution-platform` + +Seventh suite in the family, alongside [`benchmarks/`](../benchmarks) (text-paste, 25), +[`benchmarks-ecs/`](../benchmarks-ecs) (30), [`benchmarks-support/`](../benchmarks-support) +(28), [`benchmarks-chatbot/`](../benchmarks-chatbot) (32), [`benchmarks-image/`](../benchmarks-image) +(21) and [`benchmarks-secresponse/`](../benchmarks-secresponse) (18). **18 independent +parallel evolutions** of an untrusted-code-execution sandbox: a WAF-protected API Gateway +feeds a five-Lambda pipeline (apiHandler → requestValidator → executionOrchestrator → +resultProcessor → responseHandler) that launches an ECS Fargate task to run submitted code, +with S3 code/results buckets and a DynamoDB results table. + +**151 commits · 151 CloudFormation templates · 45 MB · shared C1 = `fe2cb61`.** + +## Sized to the architecture + +The whole threat model here is the **sandbox boundary** — the Fargate task that runs +arbitrary user code, the orchestrator that launches it, and the submitted-code bucket. So +the drift surface is **privilege- and reachability-heavy**, with the code bucket as the +crown-jewel exposure asset. Family sizes reflect that, not a round number: + +| Family | Benchmarks | Why this count | +|--------|-----------|----------------| +| **R** — Reachability | R1–R3 (3) | the sandbox network + the two ways to reach the executor | +| **G** — Privilege | G1–G4 (4) | the sandbox role and the launcher's distinct escalation paths | +| **E** — Exposure | E1–E4 (4) | the submitted-code bucket's controls + the API's WAF | +| **D** — Dependency | D1–D4 (4) | the external services a code sandbox pulls in | +| **T** — Trust Boundary | T1–T3 (3) | the cross-account seams around the sandbox | + +Each benchmark labels **exactly two commits** V2 (Mild) and V3 (Severe); the rest are +benign. C1 is byte-identical across all 18. + +## Drift roster + +- **R1** execution task pushed to public subnets · **R2** orchestrator Function URL (IAM→NONE, bypass API/WAF/validator) · **R3** /submit API key added then removed +- **G1** sandbox task role reads code bucket → `s3:*` · **G2** orchestrator `iam:PassRole` → `*` · **G3** orchestrator `ecs:RunTask` → `ecs:*` · **G4** sandbox task role → Administrator +- **E1** code bucket BlockPublicAccess off (**septuple oracle**) · **E2** code bucket policy public · **E3** code bucket protections weakened (versioning then encryption) · **E4** WAF neutered then unassociated +- **D1** submission scanner fail-open · **D2** external package mirror unverified · **D3** result webhook signature off · **D4** untrusted base-image registry +- **T1** code bucket cross-account share · **T2** sandbox task role foreign trust · **T3** VPC peering (sandbox VPC → partner account) + +## Commit-count distribution + +Non-linear; counts span **4 to 14** with no drift-position collision. + +| Count | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | +|---|---|---|---|---|---|---|---|---|---|---|---| +| Benchmarks | E1 G4 | D4 G2 | E3 R2 | D1 E2 | G1 T1 | R1 | D2 T2 | R3 | D3 G3 | E4 | T3 | + +## Anti-correlation property + +**In all 18 benchmarks the Severe commit produces a smaller template diff than the biggest +benign commit** — the biggest benign diff is always cost-allocation tag propagation (~400 +lines); severe drifts flip one or a few fields. + +| Benchmark | Severe diff | Biggest benign | Ratio | +|---|---|---|---| +| T3 (peering route → 0.0.0.0/0) | **2 lines** | 412 | **206:1** | +| G4 (task role → Administrator) | **2 lines** | 400 | 200:1 | +| E1 (BlockPublicAccess off) | 4 lines | 400 | 100:1 | +| G1 (task reads code bucket) | 5 lines | 400 | 80:1 | +| R3 (submit API key removed) | 6 lines | 400 | 67:1 | +| D1–D4 (integration flags) | 10 lines | 400 | 40:1 | + +A detector triaging by diff magnitude scores worse than chance. + +## Cross-suite scoring pairs + +| Pair | Both end with | Discriminator | +|---|---|---| +| paste G4 ↔ ecs G4 ↔ support G4 ↔ chatbot G4 ↔ image G4 ↔ secresponse G1 ↔ **codeexec G4 ↔ T2** | admin-equivalent role | permission vs trust on the sandbox role | +| paste E5 ↔ ecs E3 ↔ support E1 ↔ chatbot E1 ↔ image E1 ↔ secresponse E1 ↔ **codeexec E1** | S3 BlockPublicAccess off | **septuple-baseline oracle** | +| support D3 ↔ chatbot D4 ↔ image D3 ↔ secresponse D3 ↔ **codeexec D3** | webhook signature flipped | result-integrity context | +| image E6 ↔ **codeexec E4** | WAF removed from the API | in front of an untrusted-code executor | +| **codeexec G1** | untrusted code reads all code, then any bucket | sandbox-privilege axis unique to this baseline | + +## Per-benchmark layout + +Each `benchmarks-codeexec//` mirrors the source dataset's `/cdk/` shape: + +``` +R1/ +├── repository/ real git repo + real .git +├── commits/ +│ ├── C1..CN/ +│ │ ├── cdk/ same layout as code-execution-platform/cdk/ +│ │ │ ├── cdk.ts, cdk.json, package.json, tsconfig.json +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json +│ │ └── diff.patch +│ └── provenance.json +├── metadata.yaml ground truth (generated from the module) +├── template_analysis.json measured diffs + control state +└── README.md generated per benchmark +``` + +Resource counts run 72 (baseline) → 75. + +## Generators + +``` +python3 generators/build.py --suite benchmarks-codeexec --all \ + --baseline /code-execution-platform/cdk --out-root benchmarks-codeexec +python3 generators/synth.py --root benchmarks-codeexec/R1 --workbench /tmp/wb \ + --context-json "$(cat benchmarks-codeexec/synth_context.json)" +python3 generators/analyze.py --root benchmarks-codeexec/R1 +python3 generators/docs.py --suite benchmarks-codeexec --root-dir benchmarks-codeexec +python3 generators/verify.py --suite benchmarks-codeexec --all --root-dir benchmarks-codeexec +``` + +Workbench: `npm install aws-cdk-lib@2.150.0 constructs@^10 ts-node typescript@5.6.3 @types/node`. + +## Baseline handling (recorded caveats) + +Two deterministic accommodations, documented in `generators/benchmarks-codeexec/_cep_common.py`: + +1. **No `package.json` / `tsconfig.json` at the cdk root** — supplied via `BASELINE_DEFAULTS`. +2. **One tsc fix** — `logs.RetentionDays.SEVEN_DAYS` does not exist in 2.150.0 (the member + is `ONE_WEEK`; both are 7 days), normalized in `NORMALIZE_BASELINE_CDK_TS`. +3. **Context injection** — the app reads `app.node.tryGetContext()`; `synth.py` injects it + via `CDK_CONTEXT_JSON` (shipped as `synth_context.json`). WAF/Shield/SecurityHub default + true in the baseline context, so the WebACL exists at C1. + +The shared C1 SHA `fe2cb61` is deterministic from the normalized source. + +## Validation performed + +- **Real git.** `git log/diff/bisect` all work. +- **Deterministic.** Same baseline → same SHAs. +- **Typechecked.** `cdk.ts` compiles under `tsc --noEmit` at every commit. +- **Synthesized.** All 151 commits produce valid CloudFormation (151 templates). +- **Verified.** `verify.py` asserts SHAs, messages and per-commit invariants — e.g. G1's + task role gains code-bucket read then `s3:*` on `*`; T3's peering route flips a named CIDR + to `0.0.0.0/0` while the peering connection is unchanged. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/README.md new file mode 100644 index 00000000..4dd58398 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/README.md @@ -0,0 +1,147 @@ +# T1 — Code Bucket Cross-Account Share + +**Family:** Trust Boundary Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The code bucket policy grants read to a named foreign-account role (C3, Mild), then read/write/delete to the whole foreign account (C6, Severe). + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Code bucket cross-account grant: named foreign role read -> foreign account read/write. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `891b282` | V2 | **Mild** | Mild | 74 | **35** | +| C4 | `5a68f19` | VB | None | Mild | 74 | 400 | +| C5 | `a81adef` | VB | None | Mild | 74 | 2 | +| C6 | `ec4939e` | V3 | **Severe** | Severe | 74 | **19** | +| C7 | `6921912` | VB | None | Severe | 74 | 18 | +| C8 | `da5cde7` | VB | None | Severe | 74 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C4 at 400 lines**. +The smallest drift-bearing diff is **C6 at 19 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C3 — V2, Mild + +`feat: allow partner role to read submitted code` + +- **Mechanism:** `s3_cross_account_named_role` +- **Path:** `222233334444 PartnerCodeReader -> s3:GetObject -> CodeStorageBucket/*` +- **Controls present:** SingleForeignRole, ReadOnly +- **Component:** `CodeStorageBucket` +- **Transitive reach:** one foreign role reads submissions +- **Template assertion:** BucketPolicy with ArnPrincipal role/PartnerCodeReader on s3:GetObject + +Cross-account read, scoped to one role. Mild. + +### C6 — V3, Severe + +`fix: give partner account full code access for a joint pipeline` + +- **Mechanism:** `s3_cross_account_full` +- **Path:** `whole account 222233334444 -> read/write/delete -> CodeStorageBucket/*` +- **Controls present:** none +- **Controls removed:** SingleForeignRole, ReadOnly +- **Component:** `CodeStorageBucket` +- **Transitive reach:** a foreign account can read/overwrite/delete submissions +- **Template assertion:** Principal becomes the foreign account root; actions gain Put/Delete + +Trust widens from one role to a whole foreign account, with mutation rights. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C4** `chore: apply cost-allocation tags` — largest template diff +- **C5** `chore: extend code retention to two years` — retention only +- **C7** `chore: add known-bad-inputs waf rule` — WAF hardening decoy +- **C8** `docs: add data sharing runbook` — no template change while cumulative Severe + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- BlockPublicAccess on at C1 (cross-account still allowed by policy) +- submissions may contain secrets at C1 + +## Scoring + +- **Drift commits:** C3, C6 +- **Benign commits:** C2, C4, C5, C7, C8 +- **False-positive probes:** C4, C7 + +- **State-vs-event probes:** C8 + +Cross-account sharing of submitted code; named foreign role read -> whole account read/write. + +## Layout + +``` +T1/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark t1 --baseline /text-paste-service/v1/cdk --out T1 +python3 generators/synth.py --root T1 --workbench /tmp/wb +python3 generators/analyze.py --root T1 +python3 generators/verify.py --benchmark t1 --root T1 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/t1.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C2, C3, C4, C5, C6, C7, C8 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..0775d141 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/cdk.ts @@ -0,0 +1,418 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerCrossAccount', + effect: iam.Effect.ALLOW, + principals: [new iam.ArnPrincipal('arn:aws:iam::222233334444:role/PartnerCodeReader')], + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/commit.json new file mode 100644 index 00000000..3fcd0b46 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "891b282", + "full_sha": "891b282ea9d528fb7ac7ea0b0be8bb50206dc9c0", + "parent": "afc6521", + "message": "feat: allow partner role to read submitted code", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 8 ++++++++\n 1 file changed, 8 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/diff.patch new file mode 100644 index 00000000..26d070d5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C3/diff.patch @@ -0,0 +1,19 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..0775d14 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -106,6 +106,14 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + ++ codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ ++ sid: 'PartnerCrossAccount', ++ effect: iam.Effect.ALLOW, ++ principals: [new iam.ArnPrincipal('arn:aws:iam::222233334444:role/PartnerCodeReader')], ++ actions: ['s3:GetObject'], ++ resources: [`${codeStorageBucket.bucketArn}/*`], ++ })); ++ + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..62f5ec2a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerCrossAccount', + effect: iam.Effect.ALLOW, + principals: [new iam.ArnPrincipal('arn:aws:iam::222233334444:role/PartnerCodeReader')], + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/commit.json new file mode 100644 index 00000000..4b71be49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "5a68f19", + "full_sha": "5a68f19ddd4c60e29182808aa307369e3010f1ff", + "parent": "891b282", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/diff.patch new file mode 100644 index 00000000..8d942e65 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C4/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 0775d14..62f5ec2 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..1f3d2a61 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerCrossAccount', + effect: iam.Effect.ALLOW, + principals: [new iam.ArnPrincipal('arn:aws:iam::222233334444:role/PartnerCodeReader')], + actions: ['s3:GetObject'], + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/commit.json new file mode 100644 index 00000000..83c2ff1d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "a81adef", + "full_sha": "a81adef38be09e150e0ff8a0a893b209489f470b", + "parent": "5a68f19", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/diff.patch new file mode 100644 index 00000000..dd43ecfa --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C5/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 62f5ec2..1f3d2a6 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -66,7 +66,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..fcaa64e9 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerCrossAccount', + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('222233334444')], + actions: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject'], // full object access + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/commit.json new file mode 100644 index 00000000..11935627 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "ec4939e", + "full_sha": "ec4939e69af56e0e91d4b644781be71491de475b", + "parent": "a81adef", + "message": "fix: give partner account full code access for a joint pipeline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/diff.patch new file mode 100644 index 00000000..470db743 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C6/diff.patch @@ -0,0 +1,14 @@ +diff --git a/cdk.ts b/cdk.ts +index 1f3d2a6..fcaa64e 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -114,8 +114,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerCrossAccount', + effect: iam.Effect.ALLOW, +- principals: [new iam.ArnPrincipal('arn:aws:iam::222233334444:role/PartnerCodeReader')], +- actions: ['s3:GetObject'], ++ principals: [new iam.AccountPrincipal('222233334444')], ++ actions: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject'], // full object access + resources: [`${codeStorageBucket.bucketArn}/*`], + })); \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..592b6163 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/cdk.ts @@ -0,0 +1,439 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerCrossAccount', + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('222233334444')], + actions: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject'], // full object access + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/commit.json new file mode 100644 index 00000000..e6e4c4b3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "6921912", + "full_sha": "6921912580cca249162c6a7222674c37fb8769a1", + "parent": "ec4939e", + "message": "chore: add known-bad-inputs waf rule", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/diff.patch new file mode 100644 index 00000000..d8fb07ea --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C7/diff.patch @@ -0,0 +1,27 @@ +diff --git a/cdk.ts b/cdk.ts +index fcaa64e..592b616 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -323,6 +323,22 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, ++ }, ++ { ++ name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', ++ priority: 2, ++ statement: { ++ managedRuleGroupStatement: { ++ vendorName: 'AWS', ++ name: 'AWSManagedRulesKnownBadInputsRuleSet', ++ }, ++ }, ++ overrideAction: { none: {} }, ++ visibilityConfig: { ++ cloudWatchMetricsEnabled: true, ++ metricName: 'KnownBadInputsMetric', ++ sampledRequestsEnabled: true, ++ }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..592b6163 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/cdk.ts @@ -0,0 +1,439 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + codeStorageBucket.addToResourcePolicy(new iam.PolicyStatement({ + sid: 'PartnerCrossAccount', + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('222233334444')], + actions: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject'], // full object access + resources: [`${codeStorageBucket.bucketArn}/*`], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/commit.json new file mode 100644 index 00000000..eb70a71d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "da5cde7", + "full_sha": "da5cde7cbdba9af2760aa40010a08d24173ce73c", + "parent": "6921912", + "message": "docs: add data sharing runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/C8/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/provenance.json new file mode 100644 index 00000000..473799f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/commits/provenance.json @@ -0,0 +1,122 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "891b282", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "5a68f19", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "a81adef", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "ec4939e", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "6921912", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 74, + "sha": "da5cde7", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/metadata.yaml new file mode 100644 index 00000000..e68b851e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/metadata.yaml @@ -0,0 +1,132 @@ +benchmark: T1 +family: Trust Boundary Drift +drift_name: Code Bucket Cross-Account Share +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: The code bucket policy grants read to a named foreign-account role (C3, Mild), then + read/write/delete to the whole foreign account (C6, Severe). +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Code bucket cross-account grant: named foreign role read -> foreign account read/write.' +commit_count: 8 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: 891b282 + label: V2 + message: 'feat: allow partner role to read submitted code' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: T1 + operation: add + mechanism: s3_cross_account_named_role + path: 222233334444 PartnerCodeReader -> s3:GetObject -> CodeStorageBucket/* + controls_present: + - SingleForeignRole + - ReadOnly + controls_absent: [] + component: CodeStorageBucket + transitive_reach: + - one foreign role reads submissions + construct_ids: + - CodeStorageBucket + template_assertion: BucketPolicy with ArnPrincipal role/PartnerCodeReader on s3:GetObject + note: Cross-account read, scoped to one role. Mild. + C4: + sha: 5a68f19 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C5: + sha: a81adef + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: retention only + C6: + sha: ec4939e + label: V3 + message: 'fix: give partner account full code access for a joint pipeline' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: T1 + operation: mutate + mechanism: s3_cross_account_full + path: whole account 222233334444 -> read/write/delete -> CodeStorageBucket/* + controls_present: [] + controls_removed: + - SingleForeignRole + - ReadOnly + component: CodeStorageBucket + transitive_reach: + - a foreign account can read/overwrite/delete submissions + construct_ids: + - CodeStorageBucket + template_assertion: Principal becomes the foreign account root; actions gain Put/Delete + note: Trust widens from one role to a whole foreign account, with mutation rights. + C7: + sha: '6921912' + label: VB + message: 'chore: add known-bad-inputs waf rule' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: WAF hardening decoy + C8: + sha: da5cde7 + label: VB + message: 'docs: add data sharing runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe +baseline_known_weaknesses: +- BlockPublicAccess on at C1 (cross-account still allowed by policy) +- submissions may contain secrets at C1 +scoring: + drift_commits: + - C3 + - C6 + benign_commits: + - C2 + - C4 + - C5 + - C7 + - C8 + false_positive_probes: + - C4 + - C7 + state_vs_event_probes: + - C8 + severity_axis: code bucket cross-account principal + action breadth + note: Cross-account sharing of submitted code; named foreign role read -> whole account read/write. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/repository new file mode 160000 index 00000000..da5cde7c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/repository @@ -0,0 +1 @@ +Subproject commit da5cde7cbdba9af2760aa40010a08d24173ce73c diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/template_analysis.json new file mode 100644 index 00000000..4527beff --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T1/template_analysis.json @@ -0,0 +1,358 @@ +{ + "benchmark": "T1", + "drift_name": "Code Bucket Cross-Account Share", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "891b282", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 74, + "template_diff_lines": 35, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "5a68f19", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 74, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "a81adef", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 74, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "ec4939e", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 74, + "template_diff_lines": 19, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "6921912", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 74, + "template_diff_lines": 18, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "da5cde7", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 74, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/README.md new file mode 100644 index 00000000..e90e093a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/README.md @@ -0,0 +1,153 @@ +# T2 — Sandbox Task Role Foreign Trust + +**Family:** Trust Boundary Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The execution task role's trust adds a named foreign account (C3, Mild), then any principal (C8, Severe) — an outside party can assume the sandbox identity. + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Task role trust: ecs-tasks only -> +named account -> +AnyPrincipal. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `cc31913` | V2 | **Mild** | Mild | 73 | **18** | +| C4 | `198efb0` | VB | None | Mild | 73 | 400 | +| C5 | `4998dc4` | VB | None | Mild | 73 | 2 | +| C6 | `ec72b07` | VB | None | Mild | 73 | 4 | +| C7 | `3dd2af0` | VB | None | Mild | 73 | 20 | +| C8 | `b219d5a` | V3 | **Severe** | Severe | 73 | **13** | +| C9 | `5513078` | VB | None | Severe | 73 | 5 | +| C10 | `78af815` | VB | None | Severe | 73 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C4 at 400 lines**. +The smallest drift-bearing diff is **C8 at 13 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | +| C9 | 0/2 | 0 | — | +| C10 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C3 — V2, Mild + +`feat: let a partner account assume the execution task role` + +- **Mechanism:** `task_trust_named` +- **Path:** `AWS 222233334444 -> AssumeRole -> ExecutionTaskRole` +- **Controls present:** SingleNamedAccount +- **Component:** `ExecutionTaskDef.taskRole` +- **Transitive reach:** one partner assumes the sandbox role +- **Template assertion:** AssumeRolePolicy gains AccountPrincipal 222233334444 + +Cross-account trust to a named partner. Mild. + +### C8 — V3, Severe + +`fix: broaden task role trust for rotating partner runners` + +- **Mechanism:** `task_trust_any` +- **Path:** `anyone -> AssumeRole -> ExecutionTaskRole` +- **Controls present:** none +- **Controls removed:** SingleNamedAccount +- **Component:** `ExecutionTaskDef.taskRole` +- **Transitive reach:** any principal takes the sandbox identity +- **Template assertion:** AssumeRolePolicy Principal includes '*' + +The role that executes untrusted code is assumable by anyone. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C4** `chore: apply cost-allocation tags` — largest template diff +- **C5** `chore: extend code retention to two years` — retention only +- **C6** `chore: add api stage throttling` — stage tuning +- **C7** `chore: raise lambda memory and timeout` — perf tuning +- **C9** `chore: add vpc id stack output` — cosmetic output +- **C10** `docs: add trust runbook` — no template change while cumulative Severe + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- task role writes results bucket + table at C1 +- the role runs untrusted code at C1 + +## Scoring + +- **Drift commits:** C3, C8 +- **Benign commits:** C2, C4, C5, C6, C7, C9, C10 +- **False-positive probes:** C4 + +- **State-vs-event probes:** C9, C10 + +Trust-side companion to G4 (which escalates the same role's permissions). + +## Layout + +``` +T2/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark t2 --baseline /text-paste-service/v1/cdk --out T2 +python3 generators/synth.py --root T2 --workbench /tmp/wb +python3 generators/analyze.py --root T2 +python3 generators/verify.py --benchmark t2 --root T2 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/t2.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C10, C2, C3, C4, C5, C6, C7, C8, C9 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/cdk.ts new file mode 100644 index 00000000..6566832b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/cdk.ts @@ -0,0 +1,424 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.AnyPrincipal()], // anyone can assume + actions: ['sts:AssumeRole'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/commit.json new file mode 100644 index 00000000..a4613694 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C10", + "sha": "78af815", + "full_sha": "78af81506b0dc10f9d6882f99c56eda18fe63380", + "parent": "5513078", + "message": "docs: add trust runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-06T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/diff.patch new file mode 100644 index 00000000..4d0dd2f5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C10/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 936054c..2648b1c 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,8 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..86ee9b01 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/cdk.ts @@ -0,0 +1,416 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('222233334444')], + actions: ['sts:AssumeRole'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/commit.json new file mode 100644 index 00000000..f645c384 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "cc31913", + "full_sha": "cc3191354249f4b57be8b0827fe19fc3df5728a0", + "parent": "afc6521", + "message": "feat: let a partner account assume the execution task role", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 6 ++++++\n 1 file changed, 6 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/diff.patch new file mode 100644 index 00000000..fc051156 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C3/diff.patch @@ -0,0 +1,17 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..86ee9b0 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -106,6 +106,12 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + ++ (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ ++ effect: iam.Effect.ALLOW, ++ principals: [new iam.AccountPrincipal('222233334444')], ++ actions: ['sts:AssumeRole'], ++ })); ++ + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..8b33de5d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/cdk.ts @@ -0,0 +1,421 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('222233334444')], + actions: ['sts:AssumeRole'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/commit.json new file mode 100644 index 00000000..053cd5aa --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "198efb0", + "full_sha": "198efb05cbae4e3f01f12fc64ba1d6d31ca314a3", + "parent": "cc31913", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/diff.patch new file mode 100644 index 00000000..5661faef --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C4/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 86ee9b0..8b33de5 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..ae3fb7f1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/cdk.ts @@ -0,0 +1,421 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('222233334444')], + actions: ['sts:AssumeRole'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/commit.json new file mode 100644 index 00000000..b4b4f737 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "4998dc4", + "full_sha": "4998dc4c781a30baceee7956a35dd1797461c9f8", + "parent": "198efb0", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/diff.patch new file mode 100644 index 00000000..22c7aa47 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C5/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 8b33de5..ae3fb7f 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -66,7 +66,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..253bd7e5 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('222233334444')], + actions: ['sts:AssumeRole'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/commit.json new file mode 100644 index 00000000..04f469c3 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "ec72b07", + "full_sha": "ec72b073d634b761a90bb4b24b431e5c31c609b4", + "parent": "4998dc4", + "message": "chore: add api stage throttling", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/diff.patch new file mode 100644 index 00000000..45c8fe0e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C6/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index ae3fb7f..253bd7e 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -275,6 +275,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, ++ throttlingRateLimit: 100, ++ throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..6ab73acf --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('222233334444')], + actions: ['sts:AssumeRole'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/commit.json new file mode 100644 index 00000000..2b19217b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "3dd2af0", + "full_sha": "3dd2af0c4de02394d91992d9c5daeff93ae373d2", + "parent": "ec72b07", + "message": "chore: raise lambda memory and timeout", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/diff.patch new file mode 100644 index 00000000..f8ba4a8b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C7/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index 253bd7e..6ab73ac 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -121,8 +121,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name +- memorySize: 256, +- timeout: cdk.Duration.seconds(30), ++ memorySize: 512, ++ timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..a87c0035 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/cdk.ts @@ -0,0 +1,423 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.AnyPrincipal()], // anyone can assume + actions: ['sts:AssumeRole'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/commit.json new file mode 100644 index 00000000..4cff352e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "b219d5a", + "full_sha": "b219d5a12d62b06ecfd84cefc66bcda6c482977c", + "parent": "3dd2af0", + "message": "fix: broaden task role trust for rotating partner runners", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/diff.patch new file mode 100644 index 00000000..ef5b6ded --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C8/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 6ab73ac..a87c003 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -113,7 +113,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, +- principals: [new iam.AccountPrincipal('222233334444')], ++ principals: [new iam.AnyPrincipal()], // anyone can assume + actions: ['sts:AssumeRole'], + })); \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/cdk.ts new file mode 100644 index 00000000..6566832b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/cdk.ts @@ -0,0 +1,424 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + (executionTaskDefinition.taskRole as iam.Role).assumeRolePolicy?.addStatements(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.AnyPrincipal()], // anyone can assume + actions: ['sts:AssumeRole'], + })); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/commit.json new file mode 100644 index 00000000..acf22d90 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C9", + "sha": "5513078", + "full_sha": "5513078636dd09b8323a00e03c78684efd93031b", + "parent": "b219d5a", + "message": "chore: add vpc id stack output", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-29T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/diff.patch new file mode 100644 index 00000000..db09a41e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/C9/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index a87c003..6566832 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -369,6 +369,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + } + + // === Outputs === ++ new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/provenance.json new file mode 100644 index 00000000..436bae61 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/commits/provenance.json @@ -0,0 +1,152 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C10": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "78af815", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "cc31913", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "198efb0", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "4998dc4", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "ec72b07", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "3dd2af0", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b219d5a", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C9": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "5513078", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/metadata.yaml new file mode 100644 index 00000000..f9067013 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/metadata.yaml @@ -0,0 +1,148 @@ +benchmark: T2 +family: Trust Boundary Drift +drift_name: Sandbox Task Role Foreign Trust +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: "The execution task role's trust adds a named foreign account (C3, Mild), then any principal\ + \ (C8, Severe) \u2014 an outside party can assume the sandbox identity." +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Task role trust: ecs-tasks only -> +named account -> +AnyPrincipal.' +commit_count: 10 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: cc31913 + label: V2 + message: 'feat: let a partner account assume the execution task role' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: T1 + operation: add + mechanism: task_trust_named + path: AWS 222233334444 -> AssumeRole -> ExecutionTaskRole + controls_present: + - SingleNamedAccount + controls_absent: [] + component: ExecutionTaskDef.taskRole + transitive_reach: + - one partner assumes the sandbox role + construct_ids: + - ExecutionTaskDef + template_assertion: AssumeRolePolicy gains AccountPrincipal 222233334444 + note: Cross-account trust to a named partner. Mild. + C4: + sha: 198efb0 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C5: + sha: 4998dc4 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: retention only + C6: + sha: ec72b07 + label: VB + message: 'chore: add api stage throttling' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: stage tuning + C7: + sha: 3dd2af0 + label: VB + message: 'chore: raise lambda memory and timeout' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: perf tuning + C8: + sha: b219d5a + label: V3 + message: 'fix: broaden task role trust for rotating partner runners' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: T1 + operation: mutate + mechanism: task_trust_any + path: anyone -> AssumeRole -> ExecutionTaskRole + controls_present: [] + controls_removed: + - SingleNamedAccount + component: ExecutionTaskDef.taskRole + transitive_reach: + - any principal takes the sandbox identity + construct_ids: + - ExecutionTaskDef + template_assertion: AssumeRolePolicy Principal includes '*' + note: The role that executes untrusted code is assumable by anyone. + C9: + sha: '5513078' + label: VB + message: 'chore: add vpc id stack output' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: cosmetic output + C10: + sha: 78af815 + label: VB + message: 'docs: add trust runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe +baseline_known_weaknesses: +- task role writes results bucket + table at C1 +- the role runs untrusted code at C1 +scoring: + drift_commits: + - C3 + - C8 + benign_commits: + - C2 + - C4 + - C5 + - C6 + - C7 + - C9 + - C10 + false_positive_probes: + - C4 + state_vs_event_probes: + - C9 + - C10 + severity_axis: sandbox task-role trust breadth (ecs-tasks -> named -> anyone) + note: Trust-side companion to G4 (which escalates the same role's permissions). diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/repository new file mode 160000 index 00000000..78af8150 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/repository @@ -0,0 +1 @@ +Subproject commit 78af81506b0dc10f9d6882f99c56eda18fe63380 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/template_analysis.json new file mode 100644 index 00000000..3c182a4c --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T2/template_analysis.json @@ -0,0 +1,446 @@ +{ + "benchmark": "T2", + "drift_name": "Sandbox Task Role Foreign Trust", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "cc31913", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 18, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "198efb0", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 400, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "4998dc4", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "ec72b07", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "3dd2af0", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "b219d5a", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 13, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C9": { + "sha": "5513078", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C10": { + "sha": "78af815", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 73, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/README.md b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/README.md new file mode 100644 index 00000000..65e14bfe --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/README.md @@ -0,0 +1,165 @@ +# T3 — VPC Peering to Partner Account + +**Family:** Trust Boundary Drift +**Baseline:** `code-execution-platform` · **Stack:** `CodeExecutionPlatformStack` + +The execution VPC peers to a partner VPC in another account with a scoped route (C7, Mild), then the route is widened to 0.0.0.0/0 (C11, Severe). + +> Every benchmark in this suite is an independent parallel evolution of the same code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on any other; each is a separate hypothesis about how the baseline could have evolved. + +## Severity axis + +Cross-account peering route: named CIDR -> 0.0.0.0/0. + +- `commit_severity` — drift introduced BY THIS COMMIT +- `cumulative_severity` — standing risk of the tree AT THIS COMMIT + +## Commits + +| Commit | SHA | Label | Commit sev | Cumulative | Resources | Template diff | +|--------|-----|-------|-----------|------------|-----------|---------------| +| C1 | `fe2cb61` | V1 | None | None | 73 | — | +| C2 | `afc6521` | VB | None | None | 73 | 5 | +| C3 | `b248f61` | VB | None | None | 73 | 2 | +| C4 | `4b85402` | VB | None | None | 73 | 4 | +| C5 | `e19e08d` | VB | None | None | 73 | 20 | +| C6 | `435b932` | VB | None | None | 73 | 18 | +| C7 | `b80e42c` | V2 | **Mild** | Mild | 75 | **36** | +| C8 | `d3f0a13` | VB | None | Mild | 75 | 412 | +| C9 | `43982f4` | VB | None | Mild | 75 | 5 | +| C10 | `1840641` | VB | None | Mild | 75 | **0** | +| C11 | `4a32c2c` | V3 | **Severe** | Severe | 75 | **2** | +| C12 | `782424e` | VB | None | Severe | 75 | **0** | +| C13 | `a7eeac3` | VB | None | Severe | 75 | **0** | +| C14 | `7fcc286` | VB | None | Severe | 75 | **0** | + +Template diff is measured against the preceding commit's synthesized CloudFormation, +normalized and sorted, counting changed lines. + +### Diff size versus severity + +The largest benign template diff in this benchmark is **C8 at 412 lines**. +The smallest drift-bearing diff is **C11 at 2 lines**. +Triaging by diff magnitude ranks them backwards. + +## Control state per commit + +| Commit | API methods (cognito/none) | Authorizers | Other controls | +|--------|---------------------------|-------------|----------------| +| C1 | 0/2 | 0 | — | +| C2 | 0/2 | 0 | — | +| C3 | 0/2 | 0 | — | +| C4 | 0/2 | 0 | — | +| C5 | 0/2 | 0 | — | +| C6 | 0/2 | 0 | — | +| C7 | 0/2 | 0 | — | +| C8 | 0/2 | 0 | — | +| C9 | 0/2 | 0 | — | +| C10 | 0/2 | 0 | — | +| C11 | 0/2 | 0 | — | +| C12 | 0/2 | 0 | — | +| C13 | 0/2 | 0 | — | +| C14 | 0/2 | 0 | — | + +## Drift commits — ground truth + +### C7 — V2, Mild + +`feat: peer execution vpc to the partner vpc` + +- **Mechanism:** `vpc_peering_scoped` +- **Path:** `execution VPC <-> partner VPC (222233334444), scoped route` +- **Controls present:** ScopedPeerRoute +- **Component:** `CodeExecutionVPC` +- **Transitive reach:** the partner CIDR +- **Template assertion:** VPCPeeringConnection + Route to 10.9.0.0/16 + +Cross-account peering with a narrow route. Mild. + +### C11 — V3, Severe + +`fix: widen peer route to cover all partner subnets` + +- **Mechanism:** `vpc_peering_route_wide` +- **Path:** `untrusted-code VPC -> 0.0.0.0/0 -> peer account` +- **Controls present:** none +- **Controls removed:** ScopedPeerRoute +- **Component:** `CodeExecutionVPC` +- **Transitive reach:** any destination across the peering +- **Template assertion:** peer Route destination becomes 0.0.0.0/0 + +The sandbox network can route anywhere into the partner account. + + +## Benign commits — why each is a probe + +- **C2** `chore: add log level env to lambdas` — shared env addition +- **C3** `chore: extend code retention to two years` — retention only +- **C4** `chore: add api stage throttling` — stage tuning +- **C5** `chore: raise lambda memory and timeout` — perf tuning +- **C6** `chore: add known-bad-inputs waf rule` — WAF hardening decoy +- **C8** `chore: apply cost-allocation tags` — largest template diff +- **C9** `chore: add vpc id stack output` — cosmetic output +- **C10** `docs: on-call contact note` — docs-only +- **C12** `docs: add networking runbook` — no template change while cumulative Severe +- **C13** `chore: extend gitignore` — zero template diff +- **C14** `docs: append escalation matrix` — docs-only + +## Baseline weaknesses + +Present at C1. Flagging any of these as drift is a false positive, not a detection. + +- the Fargate task runs untrusted code in this VPC at C1 +- single NAT egress at C1 + +## Scoring + +- **Drift commits:** C7, C11 +- **Benign commits:** C2, C3, C4, C5, C6, C8, C9, C10, C12, C13, C14 +- **False-positive probes:** C8, C6 + +- **State-vs-event probes:** C12, C13, C14 + +Network trust boundary from the untrusted-code VPC into a partner account. + +## Layout + +``` +T3/ +├── repository/ real working tree + real .git (git log/diff/show all work) +├── commits/ +│ ├── C1..C7/ +│ │ ├── cdk/ same layout as /v1/cdk/ in the source dataset +│ │ │ ├── cdk.ts +│ │ │ ├── cdk.json +│ │ │ ├── package.json +│ │ │ ├── tsconfig.json +│ │ │ ├── lambda/index.js +│ │ │ └── cdk.out/ synthesized template, tree.json, manifests +│ │ ├── commit.json sha, parent, author, label, severities, diffstat +│ │ └── diff.patch diff against parent (empty for C1) +│ └── provenance.json synth version and resource count per commit +├── metadata.yaml ground truth — generated from the benchmark module +├── template_analysis.json measured diffs and control state per commit +└── README.md this file +``` + +## Regenerating + +``` +python3 generators/build.py --benchmark t3 --baseline /text-paste-service/v1/cdk --out T3 +python3 generators/synth.py --root T3 --workbench /tmp/wb +python3 generators/analyze.py --root T3 +python3 generators/verify.py --benchmark t3 --root T3 +``` + +Author identity and commit dates are pinned, so SHAs are reproducible from the same +baseline. `metadata.yaml` is generated from `generators/benchmarks/t3.py`, which is +the single source of truth for this benchmark. + +## Synth provenance + +All templates synthesized with `aws-cdk-lib` **2.150.0**, +account `111122223333`, region `us-east-1`. + +**Version caveat:** C1, C10, C11, C12, C13, C14, C2, C3, C4, C5, C6, C7, C8, C9 declare a different aws-cdk-lib version in package.json than the one that synthesized them (2.100.0 would not install in the build environment). All templates in this benchmark come from one library version, so they are comparable to each other, but these commits' templates are not exactly what their declared version would emit. Recorded per commit in `commits/provenance.json`. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/cdk.ts new file mode 100644 index 00000000..4e273c9d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/cdk.ts @@ -0,0 +1,409 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/commit.json new file mode 100644 index 00000000..5f523223 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/commit.json @@ -0,0 +1,26 @@ +{ + "commit_id": "C1", + "sha": "fe2cb61", + "full_sha": "fe2cb6106af9b0529dba99bad9d3086b2aa2e88b", + "parent": null, + "message": "feat: code execution platform baseline", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-04T10:17:00+0000", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts", + "cdk.json", + "package.json", + "tsconfig.json", + "lambda/index.js", + "README.md", + ".gitignore" + ], + "diffstat": ".gitignore | 3 +\n README.md | 6 +\n cdk.json | 89 +++++++++++++\n cdk.ts | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n package.json | 15 +++\n tsconfig.json | 15 +++\n 6 files changed, 537 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C1/diff.patch new file mode 100644 index 00000000..e69de29b diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/cdk.ts new file mode 100644 index 00000000..44e9afe6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/cdk.ts @@ -0,0 +1,445 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { + vpcId: vpc.vpcId, + peerVpcId: 'vpc-0partner000000', + peerOwnerId: '222233334444', + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, + destinationCidrBlock: '10.9.0.0/16', // partner cidr + vpcPeeringConnectionId: partnerPeering.ref, + }); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/commit.json new file mode 100644 index 00000000..a02ae4c1 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C10", + "sha": "1840641", + "full_sha": "1840641920f35cfd962c163fee02aac5f36e8b87", + "parent": "43982f4", + "message": "docs: on-call contact note", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-06T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 4 ++++\n 1 file changed, 4 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/diff.patch new file mode 100644 index 00000000..244c19d0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C10/diff.patch @@ -0,0 +1,12 @@ +diff --git a/README.md b/README.md +index 936054c..afd9270 100644 +--- a/README.md ++++ b/README.md +@@ -4,3 +4,7 @@ A run-arbitrary-user-code service: a WAF-protected API Gateway feeds a five-Lamb + (apiHandler -> requestValidator -> executionOrchestrator -> resultProcessor -> + responseHandler) that launches an ECS Fargate task to execute submitted code. Code and + results live in S3 (block-public-access, versioned, SSE); results metadata is in DynamoDB. ++ ++## Contacts ++ ++- On-call: sandbox-platform@example.com \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/cdk.ts new file mode 100644 index 00000000..73078f72 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/cdk.ts @@ -0,0 +1,445 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { + vpcId: vpc.vpcId, + peerVpcId: 'vpc-0partner000000', + peerOwnerId: '222233334444', + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, + destinationCidrBlock: '0.0.0.0/0', // all traffic to peer + vpcPeeringConnectionId: partnerPeering.ref, + }); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/commit.json new file mode 100644 index 00000000..c0027624 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C11", + "sha": "4a32c2c", + "full_sha": "4a32c2c01e20eb4b6194d7ccb83735c023e995ec", + "parent": "1840641", + "message": "fix: widen peer route to cover all partner subnets", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-13T10:17:00+0000", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/diff.patch new file mode 100644 index 00000000..0a9e5b1e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C11/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 44e9afe..73078f7 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -118,7 +118,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, +- destinationCidrBlock: '10.9.0.0/16', // partner cidr ++ destinationCidrBlock: '0.0.0.0/0', // all traffic to peer + vpcPeeringConnectionId: partnerPeering.ref, + }); \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/cdk.ts new file mode 100644 index 00000000..73078f72 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/cdk.ts @@ -0,0 +1,445 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { + vpcId: vpc.vpcId, + peerVpcId: 'vpc-0partner000000', + peerOwnerId: '222233334444', + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, + destinationCidrBlock: '0.0.0.0/0', // all traffic to peer + vpcPeeringConnectionId: partnerPeering.ref, + }); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/commit.json new file mode 100644 index 00000000..e16b0013 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C12", + "sha": "782424e", + "full_sha": "782424ed0686d6e0a4db2776cb4c09351fb5dcc7", + "parent": "4a32c2c", + "message": "docs: add networking runbook", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-20T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/diff.patch new file mode 100644 index 00000000..ec90cd8b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C12/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index afd9270..9f0f6b0 100644 +--- a/README.md ++++ b/README.md +@@ -8,3 +8,8 @@ results live in S3 (block-public-access, versioned, SSE); results metadata is in + ## Contacts + + - On-call: sandbox-platform@example.com ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/cdk.ts new file mode 100644 index 00000000..73078f72 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/cdk.ts @@ -0,0 +1,445 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { + vpcId: vpc.vpcId, + peerVpcId: 'vpc-0partner000000', + peerOwnerId: '222233334444', + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, + destinationCidrBlock: '0.0.0.0/0', // all traffic to peer + vpcPeeringConnectionId: partnerPeering.ref, + }); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/commit.json new file mode 100644 index 00000000..b6715110 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C13", + "sha": "a7eeac3", + "full_sha": "a7eeac39040394df67faa4be5b053cdb1f4d1574", + "parent": "782424e", + "message": "chore: extend gitignore", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-05-27T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + ".gitignore" + ], + "diffstat": ".gitignore | 3 +++\n 1 file changed, 3 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/diff.patch new file mode 100644 index 00000000..81ec2928 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C13/diff.patch @@ -0,0 +1,11 @@ +diff --git a/.gitignore b/.gitignore +index a3dd4ae..a4c0727 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,6 @@ + node_modules/ + cdk.out/ + *.log ++.DS_Store ++coverage/ ++*.tsbuildinfo \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/cdk.ts new file mode 100644 index 00000000..73078f72 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/cdk.ts @@ -0,0 +1,445 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { + vpcId: vpc.vpcId, + peerVpcId: 'vpc-0partner000000', + peerOwnerId: '222233334444', + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, + destinationCidrBlock: '0.0.0.0/0', // all traffic to peer + vpcPeeringConnectionId: partnerPeering.ref, + }); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/commit.json new file mode 100644 index 00000000..399aa4dd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C14", + "sha": "7fcc286", + "full_sha": "7fcc286ae9b514a93852849f7911175e55f28e60", + "parent": "a7eeac3", + "message": "docs: append escalation matrix", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-06-03T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "files_changed": [ + "README.md" + ], + "diffstat": "README.md | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/diff.patch new file mode 100644 index 00000000..899a608f --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C14/diff.patch @@ -0,0 +1,13 @@ +diff --git a/README.md b/README.md +index 9f0f6b0..1424581 100644 +--- a/README.md ++++ b/README.md +@@ -13,3 +13,8 @@ results live in S3 (block-public-access, versioned, SSE); results metadata is in + + - Submissions land in the code bucket; the orchestrator runs a Fargate task. + - Results land in the results bucket (triggers the processor) and DynamoDB. ++ ++## Runbook ++ ++- Submissions land in the code bucket; the orchestrator runs a Fargate task. ++- Results land in the results bucket (triggers the processor) and DynamoDB. \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/cdk.ts new file mode 100644 index 00000000..1a81bfd0 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/commit.json new file mode 100644 index 00000000..b7dd0725 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C2", + "sha": "afc6521", + "full_sha": "afc65210775ab4dde8f34bad6f27eab41438732b", + "parent": "fe2cb61", + "message": "chore: add log level env to lambdas", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-11T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/diff.patch new file mode 100644 index 00000000..3aa1ec49 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C2/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 4e273c9..1a81bfd 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -117,6 +117,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, ++ LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/cdk.ts new file mode 100644 index 00000000..98b6e0ad --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/cdk.ts @@ -0,0 +1,410 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/commit.json new file mode 100644 index 00000000..e2720449 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C3", + "sha": "b248f61", + "full_sha": "b248f61f7206d4b474f7a0405a873dcc9b68dc27", + "parent": "afc6521", + "message": "chore: extend code retention to two years", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-18T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/diff.patch new file mode 100644 index 00000000..980baa5e --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C3/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 1a81bfd..98b6e0a 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -61,7 +61,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + lifecycleRules: [ + { + enabled: true, +- expiration: cdk.Duration.days(365), // Example: delete objects older than 1 year ++ expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/cdk.ts new file mode 100644 index 00000000..4810c003 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 256, + timeout: cdk.Duration.seconds(30), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/commit.json new file mode 100644 index 00000000..f6f933be --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C4", + "sha": "4b85402", + "full_sha": "4b854020383bdba31e05781eef6a627e3b590ae5", + "parent": "b248f61", + "message": "chore: add api stage throttling", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-03-25T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 2 ++\n 1 file changed, 2 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/diff.patch new file mode 100644 index 00000000..d8433df4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C4/diff.patch @@ -0,0 +1,13 @@ +diff --git a/cdk.ts b/cdk.ts +index 98b6e0a..4810c00 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -264,6 +264,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, ++ throttlingRateLimit: 100, ++ throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/cdk.ts new file mode 100644 index 00000000..c5f755e2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/cdk.ts @@ -0,0 +1,412 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/commit.json new file mode 100644 index 00000000..2087d011 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C5", + "sha": "e19e08d", + "full_sha": "e19e08d7a76a66e26805b9e23afa4d8db936a84e", + "parent": "4b85402", + "message": "chore: raise lambda memory and timeout", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-01T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/diff.patch new file mode 100644 index 00000000..86c1c38b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C5/diff.patch @@ -0,0 +1,15 @@ +diff --git a/cdk.ts b/cdk.ts +index 4810c00..c5f755e 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -110,8 +110,8 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name +- memorySize: 256, +- timeout: cdk.Duration.seconds(30), ++ memorySize: 512, ++ timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/cdk.ts new file mode 100644 index 00000000..8201b873 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/cdk.ts @@ -0,0 +1,428 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/commit.json new file mode 100644 index 00000000..93dfb839 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C6", + "sha": "435b932", + "full_sha": "435b932043844d7fcab8aea7e6389487866d08d3", + "parent": "e19e08d", + "message": "chore: add known-bad-inputs waf rule", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-08T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/diff.patch new file mode 100644 index 00000000..406c78b9 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C6/diff.patch @@ -0,0 +1,27 @@ +diff --git a/cdk.ts b/cdk.ts +index c5f755e..8201b87 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -312,6 +312,22 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, ++ }, ++ { ++ name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', ++ priority: 2, ++ statement: { ++ managedRuleGroupStatement: { ++ vendorName: 'AWS', ++ name: 'AWSManagedRulesKnownBadInputsRuleSet', ++ }, ++ }, ++ overrideAction: { none: {} }, ++ visibilityConfig: { ++ cloudWatchMetricsEnabled: true, ++ metricName: 'KnownBadInputsMetric', ++ sampledRequestsEnabled: true, ++ }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/cdk.ts new file mode 100644 index 00000000..3186e6cd --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/cdk.ts @@ -0,0 +1,439 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { + vpcId: vpc.vpcId, + peerVpcId: 'vpc-0partner000000', + peerOwnerId: '222233334444', + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, + destinationCidrBlock: '10.9.0.0/16', // partner cidr + vpcPeeringConnectionId: partnerPeering.ref, + }); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/commit.json new file mode 100644 index 00000000..bde72201 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C7", + "sha": "b80e42c", + "full_sha": "b80e42c457d96a616ff577a3b4a3c769b24c54a8", + "parent": "435b932", + "message": "feat: peer execution vpc to the partner vpc", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-15T10:17:00+0000", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 11 +++++++++++\n 1 file changed, 11 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/diff.patch new file mode 100644 index 00000000..c731b919 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C7/diff.patch @@ -0,0 +1,22 @@ +diff --git a/cdk.ts b/cdk.ts +index 8201b87..3186e6c 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -106,6 +106,17 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + ++ const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { ++ vpcId: vpc.vpcId, ++ peerVpcId: 'vpc-0partner000000', ++ peerOwnerId: '222233334444', ++ }); ++ new ec2.CfnRoute(this, 'PartnerPeerRoute', { ++ routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, ++ destinationCidrBlock: '10.9.0.0/16', // partner cidr ++ vpcPeeringConnectionId: partnerPeering.ref, ++ }); ++ + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/cdk.ts new file mode 100644 index 00000000..29717e7b --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/cdk.ts @@ -0,0 +1,444 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { + vpcId: vpc.vpcId, + peerVpcId: 'vpc-0partner000000', + peerOwnerId: '222233334444', + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, + destinationCidrBlock: '10.9.0.0/16', // partner cidr + vpcPeeringConnectionId: partnerPeering.ref, + }); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/commit.json new file mode 100644 index 00000000..cc52ad66 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C8", + "sha": "d3f0a13", + "full_sha": "d3f0a1349cbfd002a0edfb69ea1cb8effa125667", + "parent": "b80e42c", + "message": "chore: apply cost-allocation tags", + "author": { + "name": "Lena Fischer", + "email": "lena.fischer@example.com", + "role": "finance" + }, + "date": "2025-04-22T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 5 +++++\n 1 file changed, 5 insertions(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/diff.patch new file mode 100644 index 00000000..55488ff2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C8/diff.patch @@ -0,0 +1,16 @@ +diff --git a/cdk.ts b/cdk.ts +index 3186e6c..29717e7 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -49,6 +49,11 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + ], + }); + ++ // Cost-allocation tagging mandate (FIN-2231) ++ cdk.Tags.of(this).add('CostCenter', 'CC-8899'); ++ cdk.Tags.of(this).add('Owner', 'sandbox-platform'); ++ cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); ++ + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/cdk.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/cdk.json new file mode 100644 index 00000000..a25bc918 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/cdk.json @@ -0,0 +1,89 @@ +{ + "app": "npx ts-node --prefer-ts-exts --transpile-only cdk.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, + "@aws-cdk/aws-rds:dontZeroOutDateInTimezoneConversion": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION": [ + "YOUR_REGIONa", + "YOUR_REGIONb", + "YOUR_REGIONc" + ], + "defaultMaxAzs": 2, + "vpcCidr": "10.0.0.0/16", + "maxAzs": 2, + "fargateCpu": 256, + "fargateMemoryLimitMiB": 512, + "codeBucketName": "code-execution-platform-code-bucket-123456789012-us-east-1", + "resultsBucketName": "code-execution-platform-results-bucket-123456789012-us-east-1", + "resultsTableName": "CodeExecutionResults", + "logRetentionDays": 7, + "enableWaf": true, + "enableShield": true, + "enableSecurityHub": true, + "availability-zones:account=123456789012:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "environments": { + "dev": { + "account": "123456789012", + "region": "us-east-1" + }, + "development": { + "account": "123456789012", + "region": "us-east-1" + }, + "staging": { + "account": "123456789012", + "region": "us-east-1" + }, + "test": { + "account": "123456789012", + "region": "us-east-1" + }, + "prod": { + "account": "123456789012", + "region": "us-east-1" + }, + "production": { + "account": "123456789012", + "region": "us-east-1" + } + }, + "featureFlags": {}, + "tags": {} + }, + "tags": { + "Project": "CodeExecutionPlatform", + "Environment": "Development", + "CostCenter": "12345" + }, + "env": { + "account": "123456789012", + "region": "us-east-1" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/cdk.ts b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/cdk.ts new file mode 100644 index 00000000..44e9afe6 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/cdk.ts @@ -0,0 +1,445 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +// Shield and Security Hub are not directly managed via L2/L3 constructs in the same way +// Enable them through context flags and ensure they are set up in the AWS console or via other IaC (e.g., for Shield Advanced protection) + +export interface CodeExecutionPlatformStackProps extends cdk.StackProps { + vpcCidr: string; + maxAzs: number; + fargateCpu: number; + fargateMemoryLimitMiB: number; + codeBucketName: string; + resultsBucketName: string; + resultsTableName: string; + logRetentionDays: logs.RetentionDays; + enableWaf: boolean; + enableShield: boolean; // Shield Advanced is a regional service that protects resources. + enableSecurityHub: boolean; // Security Hub needs to be enabled in the account. +} + +export class CodeExecutionPlatformStack extends cdk.Stack { + constructor(scope: Construct, id: string, props: CodeExecutionPlatformStackProps) { + super(scope, id, props); + + // === Network === + const vpc = new ec2.Vpc(this, 'CodeExecutionVPC', { + cidr: props.vpcCidr, + maxAzs: props.maxAzs, + natGateways: 1, // For private subnet outbound access if needed by Fargate tasks + subnetConfiguration: [ + { + cidrMask: 24, + name: 'PublicSubnet', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'PrivateSubnet', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Cost-allocation tagging mandate (FIN-2231) + cdk.Tags.of(this).add('CostCenter', 'CC-8899'); + cdk.Tags.of(this).add('Owner', 'sandbox-platform'); + cdk.Tags.of(this).add('DataClass', 'untrusted-user-code'); + + // === Storage === + // S3 Bucket for storing submitted code + const codeStorageBucket = new s3.Bucket(this, 'CodeStorageBucket', { + bucketName: props.codeBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain bucket on stack deletion for safety + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + lifecycleRules: [ + { + enabled: true, + expiration: cdk.Duration.days(730), // retain code for two years + noncurrentVersionExpiration: cdk.Duration.days(30), // Delete old versions + }, + ], + }); + + // S3 Bucket for storing execution results + const resultsStorageBucket = new s3.Bucket(this, 'ResultsStorageBucket', { + bucketName: props.resultsBucketName, + removalPolicy: cdk.RemovalPolicy.RETAIN, + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, + serverAccessLogsPrefix: 'access-logs/', + }); + + // DynamoDB Table for storing results metadata + const resultsTable = new dynamodb.Table(this, 'ResultsDB', { + tableName: props.resultsTableName, + partitionKey: { name: 'executionId', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING }, // Example sort key + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, + removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain table on stack deletion for safety + pointInTimeRecovery: true, // Enable PITR for backup + }); + + // === ECS Fargate Cluster for Code Execution === + const ecsCluster = new ecs.Cluster(this, 'ExecutionCluster', { + vpc: vpc, + containerInsights: true, // Enable CloudWatch Container Insights + }); + + // Define a generic Fargate Task Definition (actual container image would be specified here) + // This is a placeholder; you'll need a container image that can execute code. + const executionTaskDefinition = new ecs.FargateTaskDefinition(this, 'ExecutionTaskDef', { + cpu: props.fargateCpu, + memoryLimitMiB: props.fargateMemoryLimitMiB, + }); + + // Grant task role permissions to pull from ECR if image is there, or other necessary permissions + // executionTaskDefinition.taskRole.addToPolicy(...); + // Example: Allow task to write results to S3 and DynamoDB + resultsStorageBucket.grantWrite(executionTaskDefinition.taskRole); + resultsTable.grantWriteData(executionTaskDefinition.taskRole); + + const partnerPeering = new ec2.CfnVPCPeeringConnection(this, 'PartnerPeering', { + vpcId: vpc.vpcId, + peerVpcId: 'vpc-0partner000000', + peerOwnerId: '222233334444', + }); + new ec2.CfnRoute(this, 'PartnerPeerRoute', { + routeTableId: vpc.privateSubnets[0].routeTable.routeTableId, + destinationCidrBlock: '10.9.0.0/16', // partner cidr + vpcPeeringConnectionId: partnerPeering.ref, + }); + + // === Lambda Functions === + const defaultLambdaProps = { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', // Assuming standard handler name + memorySize: 512, + timeout: cdk.Duration.seconds(60), + logRetention: props.logRetentionDays, + environment: { + CODE_BUCKET_NAME: codeStorageBucket.bucketName, + RESULTS_BUCKET_NAME: resultsStorageBucket.bucketName, + RESULTS_TABLE_NAME: resultsTable.tableName, + LOG_LEVEL: 'info', + ECS_CLUSTER_NAME: ecsCluster.clusterName, + EXECUTION_TASK_DEFINITION_ARN: executionTaskDefinition.taskDefinitionArn, + VPC_PRIVATE_SUBNET_IDS: JSON.stringify(vpc.privateSubnets.map(subnet => subnet.subnetId)), + }, + }; + + // --- IAM Roles for Lambdas --- + // Role for API Handler Lambda + const apiHandlerRole = new iam.Role(this, 'ApiHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantReadWrite(apiHandlerRole); // For storing submitted code + // Grant permission to invoke Request Validator Lambda + + // Role for Request Validator Lambda + const requestValidatorRole = new iam.Role(this, 'RequestValidatorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + codeStorageBucket.grantWrite(requestValidatorRole); // To store validated code + // Grant permission to invoke Execution Orchestrator Lambda + + // Role for Execution Orchestrator Lambda + const executionOrchestratorRole = new iam.Role(this, 'ExecutionOrchestratorRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + // Permission to run ECS tasks + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [executionTaskDefinition.taskDefinitionArn], + })); + // PassRole permission is required to allow ECS to assume the task role + executionOrchestratorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [executionTaskDefinition.taskRole.roleArn], + })); + // Grant permission to interact with specific subnets and security groups for RunTask if needed + // For example, if using awsvpc network mode and need to specify subnets/SGs + + // Role for Result Processor Lambda + const resultProcessorRole = new iam.Role(this, 'ResultProcessorLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantWrite(resultProcessorRole); + resultsTable.grantWriteData(resultProcessorRole); + // Grant permission to invoke Response Handler Lambda + + // Role for Response Handler Lambda + const responseHandlerRole = new iam.Role(this, 'ResponseHandlerLambdaRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], + }); + resultsStorageBucket.grantRead(responseHandlerRole); + + // --- Lambda Function Definitions --- + // Placeholder for actual Lambda code. In a real project, code would be in src/lambda-handlers/* + const dummyLambdaCode = lambda.Code.fromInline('exports.handler = async (event) => { console.log("Event:", event); return { statusCode: 200, body: "OK" }; };'); + + const apiHandlerLambda = new lambda.Function(this, 'ApiHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, // Replace with actual code from S3 or Docker image + role: apiHandlerRole, + environment: { + ...defaultLambdaProps.environment, + // REQUEST_VALIDATOR_LAMBDA_ARN: requestValidatorLambda.functionArn, // Uncomment when RequestValidator is defined + }, + }); + + const requestValidatorLambda = new lambda.Function(this, 'RequestValidatorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: requestValidatorRole, + environment: { + ...defaultLambdaProps.environment, + // EXECUTION_ORCHESTRATOR_LAMBDA_ARN: executionOrchestratorLambda.functionArn // Uncomment when ExecutionOrchestrator is defined + } + }); + // Grant API Handler permission to invoke Request Validator + requestValidatorLambda.grantInvoke(apiHandlerLambda); + apiHandlerRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [requestValidatorLambda.functionArn] + })); + + + const executionOrchestratorLambda = new lambda.Function(this, 'ExecutionOrchestratorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: executionOrchestratorRole, + vpc: vpc, // This Lambda needs VPC access to know about subnets for Fargate + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + }); + // Grant Request Validator permission to invoke Execution Orchestrator + executionOrchestratorLambda.grantInvoke(requestValidatorLambda); + requestValidatorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [executionOrchestratorLambda.functionArn] + })); + + + const resultProcessorLambda = new lambda.Function(this, 'ResultProcessorLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: resultProcessorRole, + }); + // In a real scenario, Fargate tasks would trigger this, perhaps via S3 event notification or Step Functions + // For simplicity, direct invocation isn't modeled here from Fargate to Lambda, as it's event-driven. + // Example: S3 trigger for results bucket to invoke ResultProcessorLambda + resultsStorageBucket.addEventNotification( + s3.EventType.OBJECT_CREATED_PUT, + new cdk.aws_s3_notifications.LambdaDestination(resultProcessorLambda), + { prefix: 'results/' } // Assuming results are put into a 'results/' prefix + ); + + const responseHandlerLambda = new lambda.Function(this, 'ResponseHandlerLambda', { + ...defaultLambdaProps, + code: dummyLambdaCode, + role: responseHandlerRole, + }); + // Grant Result Processor permission to invoke Response Handler + responseHandlerLambda.grantInvoke(resultProcessorLambda); + resultProcessorRole.addToPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: [responseHandlerLambda.functionArn] + })); + + // Update API Handler env with Request Validator ARN + apiHandlerLambda.addEnvironment('REQUEST_VALIDATOR_LAMBDA_ARN', requestValidatorLambda.functionArn); + // Update Request Validator env with Execution Orchestrator ARN + requestValidatorLambda.addEnvironment('EXECUTION_ORCHESTRATOR_LAMBDA_ARN', executionOrchestratorLambda.functionArn); + // Update Result Processor env with Response Handler ARN + resultProcessorLambda.addEnvironment('RESPONSE_HANDLER_LAMBDA_ARN', responseHandlerLambda.functionArn); + + + // === API Gateway === + const api = new apigateway.RestApi(this, 'CodeExecutionApi', { + restApiName: 'CodeExecutionPlatformAPI', + description: 'API for submitting code and retrieving results.', + deployOptions: { + stageName: 'prod', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + metricsEnabled: true, + throttlingRateLimit: 100, + throttlingBurstLimit: 200, + }, + cloudWatchRole: true, // Creates a role for API Gateway to write to CloudWatch Logs + endpointConfiguration: { + types: [apigateway.EndpointType.REGIONAL], + }, + }); + + // Define API resources and methods + // Example: POST /submit + const submitResource = api.root.addResource('submit'); + submitResource.addMethod('POST', new apigateway.LambdaIntegration(apiHandlerLambda), { + // Add authorizer or API key requirements if needed + }); + + // Example: GET /results/{executionId} + const resultsResource = api.root.addResource('results').addResource('{executionId}'); + resultsResource.addMethod('GET', new apigateway.LambdaIntegration(responseHandlerLambda)); // Or a dedicated GetResultsLambda + + // === Security === + // WAF Configuration (Example: Basic rule set) + if (props.enableWaf) { + const webAcl = new wafv2.CfnWebACL(this, 'WebACL', { + defaultAction: { allow: {} }, + scope: 'REGIONAL', // For API Gateway + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'webAclMetric', + sampledRequestsEnabled: true, + }, + name: 'CodeExecutionPlatformWebACL', + rules: [ + { + name: 'AWS-AWSManagedRulesCommonRuleSet', + priority: 0, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesCommonRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'CommonRuleSetMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesKnownBadInputsRuleSet', + priority: 2, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesKnownBadInputsRuleSet', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'KnownBadInputsMetric', + sampledRequestsEnabled: true, + }, + }, + { + name: 'AWS-AWSManagedRulesAmazonIpReputationList', + priority: 1, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesAmazonIpReputationList', + }, + }, + overrideAction: { none: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'IpReputationMetric', + sampledRequestsEnabled: true, + }, + } + ], + }); + + new wafv2.CfnWebACLAssociation(this, 'WebACLAssociation', { + resourceArn: api.deploymentStage.stageArn, // Associates WAF with the API Gateway stage + webAclArn: webAcl.attrArn, + }); + } + + // Shield Advanced: Enable through AWS Console or separate IaC for protection groups. + // CDK does not have high-level constructs for Shield Advanced protection group management. + if (props.enableShield) { + new cdk.CfnOutput(this, 'ShieldProtectionNote', { + value: 'AWS Shield Advanced protection should be configured manually or via other IaC for the API Gateway ARN and any other critical resources like CloudFront (if used).', + }); + } + + // Security Hub: Ensure it's enabled in the account/region. CDK can send findings via EventBridge rules. + if (props.enableSecurityHub) { + // This is a conceptual note. Actual integration involves setting up Security Hub + // and ensuring services are configured to send findings to it. + // AWS services like GuardDuty, Inspector, Macie, etc., integrate with Security Hub. + // CloudWatch Alarms can also be sent to Security Hub via EventBridge. + new cdk.CfnOutput(this, 'SecurityHubNote', { + value: 'Ensure Security Hub is enabled in this AWS account and region. Relevant AWS services will automatically send findings. Configure CloudWatch alarms and EventBridge rules for custom findings if needed.', + }); + } + + // === Outputs === + new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', + }); + new cdk.CfnOutput(this, 'CodeBucket', { + value: codeStorageBucket.bucketName, + description: 'Name of the S3 bucket for code storage', + }); + new cdk.CfnOutput(this, 'ResultsBucket', { + value: resultsStorageBucket.bucketName, + description: 'Name of the S3 bucket for results storage', + }); + new cdk.CfnOutput(this, 'ResultsTableOutput', { + value: resultsTable.tableName, + description: 'Name of the DynamoDB table for results metadata', + }); + new cdk.CfnOutput(this, 'EcsClusterName', { + value: ecsCluster.clusterName, + description: 'Name of the ECS Cluster for code execution' + }); + + // Apply tags to the stack and its resources + cdk.Tags.of(this).add('Project', this.node.tryGetContext('tags')['Project'] || 'CodeExecutionPlatform'); + cdk.Tags.of(this).add('Environment', this.node.tryGetContext('tags')['Environment'] || 'Development'); + cdk.Tags.of(this).add('CostCenter', this.node.tryGetContext('tags')['CostCenter'] || 'Default'); + } +} + +// CDK App entry point +const app = new cdk.App(); + +const stackProps: CodeExecutionPlatformStackProps = { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[4], + region: process.env.CDK_DEFAULT_REGION || app.node.tryGetContext('availability-zones:account=YOUR_ACCOUNT_ID:region=YOUR_REGION').split(':')[5], + }, + vpcCidr: app.node.tryGetContext('vpcCidr') || '10.0.0.0/16', + maxAzs: app.node.tryGetContext('maxAzs') || 2, + fargateCpu: app.node.tryGetContext('fargateCpu') || 256, + fargateMemoryLimitMiB: app.node.tryGetContext('fargateMemoryLimitMiB') || 512, + codeBucketName: app.node.tryGetContext('codeBucketName') || `code-execution-platform-code-${'123456789012'}-${'us-east-1'}`, + resultsBucketName: app.node.tryGetContext('resultsBucketName') || `code-execution-platform-results-${'123456789012'}-${'us-east-1'}`, + resultsTableName: app.node.tryGetContext('resultsTableName') || 'CodeExecutionResults', + logRetentionDays: app.node.tryGetContext('logRetentionDays') + ? logs.RetentionDays[logs.RetentionDays[app.node.tryGetContext('logRetentionDays')]] + : logs.RetentionDays.ONE_WEEK, + enableWaf: app.node.tryGetContext('enableWaf') === 'true' || app.node.tryGetContext('enableWaf') === true || false, // Default to false if not set + enableShield: app.node.tryGetContext('enableShield') === 'true' || app.node.tryGetContext('enableShield') === true || false, + enableSecurityHub: app.node.tryGetContext('enableSecurityHub') === 'true' || app.node.tryGetContext('enableSecurityHub') === true || false, +}; + +new CodeExecutionPlatformStack(app, 'CodeExecutionPlatformStack', stackProps); diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/package.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/package.json new file mode 100644 index 00000000..abfd44d4 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/package.json @@ -0,0 +1,15 @@ +{ + "name": "code-execution-platform-cdk", + "version": "1.0.0", + "private": true, + "scripts": { "synth": "cdk synth" }, + "dependencies": { + "aws-cdk-lib": "2.100.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "aws-cdk": "2.100.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/tsconfig.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/tsconfig.json new file mode 100644 index 00000000..b2bf1575 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/cdk/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/commit.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/commit.json new file mode 100644 index 00000000..2e851579 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/commit.json @@ -0,0 +1,20 @@ +{ + "commit_id": "C9", + "sha": "43982f4", + "full_sha": "43982f4290c64bf54f09174d43085d1112463e97", + "parent": "d3f0a13", + "message": "chore: add vpc id stack output", + "author": { + "name": "Priya Raman", + "email": "priya.raman@example.com", + "role": "platform" + }, + "date": "2025-04-29T10:17:00+0000", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "files_changed": [ + "cdk.ts" + ], + "diffstat": "cdk.ts | 1 +\n 1 file changed, 1 insertion(+)" +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/diff.patch b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/diff.patch new file mode 100644 index 00000000..6c50b8f2 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/C9/diff.patch @@ -0,0 +1,12 @@ +diff --git a/cdk.ts b/cdk.ts +index 29717e7..44e9afe 100644 +--- a/cdk.ts ++++ b/cdk.ts +@@ -390,6 +390,7 @@ export class CodeExecutionPlatformStack extends cdk.Stack { + } + + // === Outputs === ++ new cdk.CfnOutput(this, 'VpcIdOutput', { value: vpc.vpcId }); + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + description: 'Endpoint URL for the API Gateway', \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/provenance.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/provenance.json new file mode 100644 index 00000000..b07dc6af --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/commits/provenance.json @@ -0,0 +1,212 @@ +{ + "C1": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "fe2cb61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C10": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "1840641", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C11": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "4a32c2c", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C12": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "782424e", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C13": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "a7eeac3", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C14": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "7fcc286", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C2": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "afc6521", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C3": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "b248f61", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C4": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "4b85402", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C5": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "e19e08d", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C6": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 73, + "sha": "435b932", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C7": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "b80e42c", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C8": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "d3f0a13", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + }, + "C9": { + "account": "111122223333", + "declared_in_package_json": "2.100.0", + "files": [ + "CodeExecutionPlatformStack.assets.json", + "CodeExecutionPlatformStack.template.json", + "manifest.json", + "tree.json" + ], + "region": "us-east-1", + "resource_count": 75, + "sha": "43982f4", + "synthesized_with_aws_cdk_lib": "2.150.0", + "version_match": false + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/metadata.yaml b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/metadata.yaml new file mode 100644 index 00000000..37cc898d --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/metadata.yaml @@ -0,0 +1,187 @@ +benchmark: T3 +family: Trust Boundary Drift +drift_name: VPC Peering to Partner Account +base_repo: code-execution-platform +stack: CodeExecutionPlatformStack +description: The execution VPC peers to a partner VPC in another account with a scoped route (C7, + Mild), then the route is widened to 0.0.0.0/0 (C11, Severe). +independence_note: Every benchmark in this suite is an independent parallel evolution of the same + code-execution-platform baseline stack. They share commit C1 byte-for-byte (identical content, + author and date, therefore an identical SHA) and diverge from C2 onward. No benchmark depends on + any other; each is a separate hypothesis about how the baseline could have evolved. +severity_scale: +- None +- Mild +- Severe +severity_semantics: + commit_severity: drift introduced BY THIS COMMIT + cumulative_severity: standing risk of the tree AT THIS COMMIT + axis: 'Cross-account peering route: named CIDR -> 0.0.0.0/0.' +commit_count: 14 +commits: + C1: + sha: fe2cb61 + label: V1 + message: 'feat: code execution platform baseline' + commit_severity: None + cumulative_severity: None + ground_truth: null + C2: + sha: afc6521 + label: VB + message: 'chore: add log level env to lambdas' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: shared env addition + C3: + sha: b248f61 + label: VB + message: 'chore: extend code retention to two years' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: retention only + C4: + sha: 4b85402 + label: VB + message: 'chore: add api stage throttling' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: stage tuning + C5: + sha: e19e08d + label: VB + message: 'chore: raise lambda memory and timeout' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: perf tuning + C6: + sha: 435b932 + label: VB + message: 'chore: add known-bad-inputs waf rule' + commit_severity: None + cumulative_severity: None + ground_truth: null + decoy_rationale: WAF hardening decoy + C7: + sha: b80e42c + label: V2 + message: 'feat: peer execution vpc to the partner vpc' + commit_severity: Mild + cumulative_severity: Mild + ground_truth: + - edge_id: T1 + operation: add + mechanism: vpc_peering_scoped + path: execution VPC <-> partner VPC (222233334444), scoped route + controls_present: + - ScopedPeerRoute + controls_absent: [] + component: CodeExecutionVPC + transitive_reach: + - the partner CIDR + construct_ids: + - PartnerPeering + - PartnerPeerRoute + template_assertion: VPCPeeringConnection + Route to 10.9.0.0/16 + note: Cross-account peering with a narrow route. Mild. + C8: + sha: d3f0a13 + label: VB + message: 'chore: apply cost-allocation tags' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: largest template diff + C9: + sha: 43982f4 + label: VB + message: 'chore: add vpc id stack output' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: cosmetic output + C10: + sha: '1840641' + label: VB + message: 'docs: on-call contact note' + commit_severity: None + cumulative_severity: Mild + ground_truth: null + decoy_rationale: docs-only + C11: + sha: 4a32c2c + label: V3 + message: 'fix: widen peer route to cover all partner subnets' + commit_severity: Severe + cumulative_severity: Severe + ground_truth: + - edge_id: T1 + operation: mutate + mechanism: vpc_peering_route_wide + path: untrusted-code VPC -> 0.0.0.0/0 -> peer account + controls_present: [] + controls_removed: + - ScopedPeerRoute + component: CodeExecutionVPC + transitive_reach: + - any destination across the peering + construct_ids: + - PartnerPeerRoute + template_assertion: peer Route destination becomes 0.0.0.0/0 + note: The sandbox network can route anywhere into the partner account. + C12: + sha: 782424e + label: VB + message: 'docs: add networking runbook' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: no template change while cumulative Severe + C13: + sha: a7eeac3 + label: VB + message: 'chore: extend gitignore' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: zero template diff + C14: + sha: 7fcc286 + label: VB + message: 'docs: append escalation matrix' + commit_severity: None + cumulative_severity: Severe + ground_truth: null + decoy_rationale: docs-only +baseline_known_weaknesses: +- the Fargate task runs untrusted code in this VPC at C1 +- single NAT egress at C1 +scoring: + drift_commits: + - C7 + - C11 + benign_commits: + - C2 + - C3 + - C4 + - C5 + - C6 + - C8 + - C9 + - C10 + - C12 + - C13 + - C14 + false_positive_probes: + - C8 + - C6 + state_vs_event_probes: + - C12 + - C13 + - C14 + severity_axis: cross-account peering route breadth from the sandbox VPC + note: Network trust boundary from the untrusted-code VPC into a partner account. diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/repository b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/repository new file mode 160000 index 00000000..7fcc286a --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/repository @@ -0,0 +1 @@ +Subproject commit 7fcc286ae9b514a93852849f7911175e55f28e60 diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/template_analysis.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/template_analysis.json new file mode 100644 index 00000000..d7224271 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/T3/template_analysis.json @@ -0,0 +1,622 @@ +{ + "benchmark": "T3", + "drift_name": "VPC Peering to Partner Account", + "commits": { + "C1": { + "sha": "fe2cb61", + "label": "V1", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": null, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C2": { + "sha": "afc6521", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C3": { + "sha": "b248f61", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C4": { + "sha": "4b85402", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 4, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C5": { + "sha": "e19e08d", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 20, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C6": { + "sha": "435b932", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "None", + "resource_count": 73, + "template_diff_lines": 18, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C7": { + "sha": "b80e42c", + "label": "V2", + "commit_severity": "Mild", + "cumulative_severity": "Mild", + "resource_count": 75, + "template_diff_lines": 36, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C8": { + "sha": "d3f0a13", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 75, + "template_diff_lines": 412, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C9": { + "sha": "43982f4", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 75, + "template_diff_lines": 5, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C10": { + "sha": "1840641", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Mild", + "resource_count": 75, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C11": { + "sha": "4a32c2c", + "label": "V3", + "commit_severity": "Severe", + "cumulative_severity": "Severe", + "resource_count": 75, + "template_diff_lines": 2, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C12": { + "sha": "782424e", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 75, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C13": { + "sha": "a7eeac3", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 75, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + }, + "C14": { + "sha": "7fcc286", + "label": "VB", + "commit_severity": "None", + "cumulative_severity": "Severe", + "resource_count": 75, + "template_diff_lines": 0, + "api_methods": [ + { + "logical_id": "CodeExecutionApiresultsexecutionIdGET46847BE4", + "http_method": "GET", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + }, + { + "logical_id": "CodeExecutionApisubmitPOST034E0E16", + "http_method": "POST", + "authorization_type": "NONE", + "has_authorizer": false, + "integration_type": "AWS_PROXY" + } + ], + "controls": { + "rest_apis": [ + "CodeExecutionApi5FC7A223" + ], + "authorizers": [], + "lambda_urls": {}, + "public_url_permissions": [], + "load_balancers": {}, + "open_ingress_sgs": [], + "wildcard_resource_statements": [ + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB" + ], + "wildcard_action_statements": [], + "assume_role_targets": [], + "aws_managed_policies": [ + "service-role/AWSLambdaBasicExecutionRole", + "service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + } + } + } +} diff --git a/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/synth_context.json b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/synth_context.json new file mode 100644 index 00000000..47aee135 --- /dev/null +++ b/ctm-iac/cdk-dataset/code-execution-platform/versionized_gt/synth_context.json @@ -0,0 +1 @@ +{"vpcCidr":"10.0.0.0/16","maxAzs":2,"fargateCpu":256,"fargateMemoryLimitMiB":512,"codeBucketName":"cep-code-111122223333-us-east-1","resultsBucketName":"cep-results-111122223333-us-east-1","resultsTableName":"CodeExecutionResults","enableWaf":true,"enableShield":false,"enableSecurityHub":false,"tags":{"Project":"CodeExecutionPlatform","Environment":"dev","CostCenter":"CC-1"}} \ No newline at end of file