import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; import { EnvName, prefix } from "./config"; import { InstanceRole } from "./constructs/instance-role"; import { AL2023_ARM64_SSM_CONTEXT_KEY, cachedArm64AmazonLinux2023, } from "./constructs/ami-cache"; export interface OpenSweStackProps extends cdk.StackProps { /** open-swe environment — drives the `open-swe--*` resource naming. */ readonly envName: EnvName; } /** * Per-env open-swe stack (`open-swe-dev` / `open-swe-prod`). Resource names are * prefixed `open-swe--*`. * * T3 scope: the per-env EC2 instance role + the wired-but-not-yet-instantiated * AMI cache helper. The EC2 instance, ALB target groups, listener rules, SG, * Route53 and NAT come at T12 — this stack is the synth-able shell they plug * into. */ export class OpenSweStack extends cdk.Stack { public readonly instanceRole: InstanceRole; constructor(scope: Construct, id: string, props: OpenSweStackProps) { super(scope, id, props); const envName = props.envName; const p = prefix(envName); cdk.Tags.of(this).add("project", "open-swe"); cdk.Tags.of(this).add("env", envName); cdk.Tags.of(this).add("ManagedBy", "cdk"); // Per-env least-privilege EC2 instance role (open-swe--instance-role). this.instanceRole = new InstanceRole(this, "Instance", envName); // AMI cache discipline (see lib/constructs/ami-cache.ts). T3 is synth-only: // resolve + surface the pinned AMI id ONLY when it is already cached in // cdk.context.json, so synth never makes a live SSM call. T12 consumes // `cachedArm64AmazonLinux2023()` for the actual ec2.Instance. if (this.node.tryGetContext(AL2023_ARM64_SSM_CONTEXT_KEY) !== undefined) { const amiId = cachedArm64AmazonLinux2023().getImage(this).imageId; new cdk.CfnOutput(this, "PinnedAmiId", { value: amiId, description: "Cached AL2023 ARM64 AMI id (pinned in cdk.context.json; consumed by the T12 EC2 instance).", }); } new cdk.CfnOutput(this, "InstanceRoleArn", { value: this.instanceRole.role.roleArn, description: `${p} EC2 instance role ARN.`, }); } }