import * as cdk from "aws-cdk-lib"; import * as cfninc from "aws-cdk-lib/cloudformation-include"; import * as path from "path"; import { Construct } from "constructs"; export interface DeploySubstrateStackProps extends cdk.StackProps { /** * Create the GitHub OIDC identity provider in this account. Leave false * when the provider already exists (seahaven-prod and seahaven-dev both * have it from their githubdeploy-* role provisioning) - an account can * only hold ONE provider per URL, so creating a duplicate fails the deploy. * Set true only for a brand-new account with no OIDC provider yet. */ createOidcProvider?: boolean; } /** * Per-account GitHub Actions deploy substrate: the shared account-level * resources every SAM deploy pipeline needs - * - GitHub OIDC identity provider (conditional, see props), * - `seahaven-lambda-execution-boundary` permissions boundary (the ceiling * applied to every SAM-generated Lambda execution role), * - `github-cfn-execution-role` (the shared CloudFormation execution role * that cd-sam callers pass as cfn-role-arn), plus * `seahaven-cfn-exec-iam-management`, the attached managed policy holding * that role's boundary-gated IAM statements (separated from the inline * policies to stay under IAM's 10,240-byte per-role inline limit). * * Deliberately NOT here: per-repo githubdeploy-* roles. Those are provisioned * per repo at migration/onboarding time (deploy-role-first playbook) so an * account never accumulates trust relationships for repos that do not deploy * to it. * * The resources come verbatim from the management account's reviewed * oidc-deploy-roles.yaml substrate section via cloudformation-include, so the * policy JSON that passed cross-review and security review deploys unchanged. * See lib/deploy-substrate/deploy-substrate.template.yaml for the provenance * and drift warning (mgmt's copy stays source of truth for 328440206208 until * its stacks finish migrating out). * * Deploy-order note: the boundary and the execution role live in the SAME * stack, and the role carries an explicit DependsOn on the boundary (the * role only names the boundary ARN inside Condition strings, so CFN would * otherwise infer no creation edge). App stacks (payments-dashboard, * front-integrations, sh-openswe-traces, ...) can only target this account * AFTER this stack is deployed there. */ export class DeploySubstrateStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: DeploySubstrateStackProps) { super(scope, id, props); new cfninc.CfnInclude(this, "Substrate", { templateFile: path.join( __dirname, "deploy-substrate", "deploy-substrate.template.yaml", ), parameters: { CreateOIDCProvider: props?.createOidcProvider ? "true" : "false", }, }); cdk.Tags.of(this).add("Project", "account-baseline"); cdk.Tags.of(this).add("Owner", "adam@seahavenind.com"); cdk.Tags.of(this).add("ManagedBy", "cdk"); } }