PR#1 of the AWS migration. CDK TypeScript app under /infra: stacks open-swe-iam (four per-env GitHub-OIDC deploy roles) + open-swe-dev/-prod (per-env EC2 instance role + AMI cache). aws-cdk-lib pinned exact 2.260.0; kebab naming Aspect + 15 tests. IAM is synth-only (NOT deployed). Cleared the Phase-1 security gates: - T4 GPT-4.1 IAM cross-review (StringEquals trust; cdk-hnb659fds-* wildcard kept as org convention; AWS-RunShellScript timeboxed to T19). - T5 /sh-security-review: deploy roles split PER-ENV with env-scoped OIDC trust (dev=branch ref+tag dev, prod=environment:prod+tag prod) so a dev token cannot reach prod; re-verified block:false. |
||
|---|---|---|
| .. | ||
| bin | ||
| lib | ||
| test | ||
| .gitignore | ||
| cdk.context.json | ||
| cdk.json | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
open-swe infra (CDK TypeScript)
AWS infrastructure for the Open SWE → AWS migration. Synth-only at this stage —
nothing here is deployed yet. All IAM is applied only after the Phase-1 security
gate (T4 GPT-4.1 IAM cross-review + T5 /sh-security-review) clears (T6).
Layout
infra/
├── bin/
│ └── app.ts # CDK app entry — instantiates the 3 stacks, applies the naming Aspect
├── lib/
│ ├── config.ts # account/region/org constants, env type, OIDC trust subjects
│ ├── open-swe-iam-stack.ts # account-level: shared OIDC deploy roles
│ ├── open-swe-stack.ts # per-env stack (instance role + AMI cache wiring)
│ ├── aspects/
│ │ └── kebab-naming-aspect.ts # fails synth on any non-kebab-case explicit name
│ └── constructs/
│ ├── github-deploy-roles.ts # githubdeploy-open-swe-infra + githubdeploy-open-swe-app
│ ├── instance-role.ts # open-swe-<env>-instance-role (least-privilege)
│ └── ami-cache.ts # cached ARM64 AL2023 helper + EBS/AMI discipline docs
├── test/
│ └── kebab-naming-aspect.test.ts # jest: Aspect passes conforming names, flags bad ones
├── cdk.json
├── cdk.context.json # COMMITTED — pins the AMI (see AMI cache discipline)
├── package.json # aws-cdk-lib pinned EXACT (2.260.0)
├── tsconfig.json
├── jest.config.js
└── .gitignore
Stacks
| Stack name (kebab) | Construct | Contents |
|---|---|---|
open-swe-iam |
OpenSweIamStack |
Account-level shared GitHub OIDC deploy roles (singletons). |
open-swe-dev |
OpenSweStack (envName: dev) |
open-swe-dev-instance-role + AMI-cache wiring. EC2/ALB/etc. land at T12. |
open-swe-prod |
OpenSweStack (envName: prod) |
open-swe-prod-instance-role + AMI-cache wiring. |
Account 328440206208, region us-east-1. Stack names are set explicitly so CDK
never defaults to PascalCase; resource names follow open-swe-<env>-*.
The two env stacks (
open-swe-dev/open-swe-prod) are the required pair. The shared OIDC deploy roles are account-wide singletons (oneRoleNameeach), so they live in their own dedicatedopen-swe-iamstack rather than being duplicated across the env stacks — and that stack deploys first (see ordering).
IAM roles defined (unapplied)
githubdeploy-open-swe-infra— GitHub OIDC role for CDK/CFN infra deploys. Trust scoped torepo:Sea-Haven-Industries/open-sweon themain/devbranches only. Permission is the org-standard CDK pattern:sts:AssumeRoleon the CDK bootstrap roles (cdk-hnb659fds-*) — the real CFN/IAM/resource scope lives in the bootstrapcfn-exec-role, not in this role.githubdeploy-open-swe-app— GitHub OIDC role for app deploys. Tag-scopedssm:SendCommand(instances taggedproject=open-swe+env in {dev,prod}) + read-only access to theopen-swe-<env>-assetsS3 artifact buckets.open-swe-<env>-instance-role— EC2 instance role, least-privilege: readopen-swe-<env>-assets(S3), read/open-swe-<env>/*(SSM), readopen-swe-<env>/*(Secrets Manager), put/open-swe/<env>/*CloudWatch Logs, plusAmazonSSMManagedInstanceCorefor SSM agent registration. No admin.
The GitHub OIDC provider already exists account-wide (created for seahaven-site); it is referenced by ARN, never re-created.
Kebab-case naming Aspect
KebabNamingAspect (applied app-wide in bin/app.ts) fails synth via
Annotations.addError when a stack name or an explicit physical resource name
(RoleName, BucketName, …) is not kebab-case. Path-style names (Secrets
Manager a/b, SSM /a/b, log groups /aws/.../x) are validated per /-segment.
CDK logical construct ids are intentionally NOT validated (they are conventionally
PascalCase). Covered by test/kebab-naming-aspect.test.ts.
AMI cache discipline (EBS-fix plumbing — stub for T12)
cachedArm64AmazonLinux2023() (in lib/constructs/ami-cache.ts) returns an
ARM64 Amazon Linux 2023 image with cachedInContext: true, so the resolved AMI
id is pinned in the committed cdk.context.json. Without the pin, every deploy
could pick up a newer AL2023 release → AMI change → EC2 instance replacement
(the file-share data-loss root cause — memory feedback_inline_ebs_volumes).
Design intent documented in code for T12 to plug into:
userDataCausesReplacement: trueis the deliberate choice — user-data is provisioning-only and carries no durable state.- No durable state on the box → no RETAIN volume. The in-memory langgraph
store is rebuilt on every boot from S3 + Secrets Manager / SSM, so there is
intentionally no standalone
ec2.Volume+removalPolicy.RETAIN. The goal is replacement-tolerance, not avoidance. - Snapshot-before-replace still applies operationally at T12: snapshot the
root volume and wait
state=completedbefore any replacing deploy, and re-verify "no local-only durable state" first.
Refresh the AMI pin deliberately:
cdk context --reset 'ssm:account=328440206208:parameterName=/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64:region=us-east-1'
cdk synth # review the diff — it WILL show "requires replacement"
The committed
cdk.context.jsonships a dummy-but-valid-shaped AMI id (ami-00000000000000000) socdk synthresolves the cache locally without any live AWS call. Replace it with the real resolved id when T8/T12 build the AMI.
Commands
npm install
npx cdk synth open-swe-iam
npx cdk synth open-swe-dev
npx cdk synth open-swe-prod
npm test # jest — naming Aspect
Deploy ordering (when the gate clears — NOT yet)
open-swe-iamfirst — creategithubdeploy-open-swe-infra+ set the repoAWS_DEPLOY_ROLE_ARNsecret before any infra/secrets CI step (BLOCK#3).- Security gate — T4 GPT-4.1 IAM cross-review + T5
/sh-security-reviewon the synth; resolve every confirmed critical/high. - IAM applied (T6) — only after the gate.
- Env stacks (
open-swe-dev, thenopen-swe-prod) build out at T12+, prod gated by a GitHub Environment manual approval.
Version policy
aws-cdk-lib is pinned EXACT (2.260.0) — no ^/~. Dependabot keeps it
current; CI (npm ci + cdk synth) + dependency review gate each bump. See
aws-infrastructure.md "CDK Version Policy" and memory
feedback_cdk_lib_bundled_deps.