diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 426954e8..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,82 +0,0 @@ -version: 2 -updates: - # Root npm dependencies (Eleventy site) - - package-ecosystem: "npm" - directory: "/" - schedule: - interval: "weekly" - cooldown: - default-days: 7 - open-pull-requests-limit: 10 - groups: - dev-dependencies: - dependency-type: "development" - production-dependencies: - dependency-type: "production" - - # CDK npm dependencies - - package-ecosystem: "npm" - directory: "/cloudformation/scenarios/localgov-drupal/cdk" - schedule: - interval: "weekly" - cooldown: - default-days: 7 - open-pull-requests-limit: 5 - groups: - aws-cdk: - patterns: - - "aws-cdk*" - - "@aws-cdk/*" - - "constructs" - - # Drupal composer dependencies - - package-ecosystem: "composer" - directory: "/cloudformation/scenarios/localgov-drupal/drupal" - schedule: - interval: "weekly" - cooldown: - default-days: 7 - open-pull-requests-limit: 10 - groups: - drupal-core: - patterns: - - "drupal/core*" - drupal-contrib: - patterns: - - "drupal/*" - exclude-patterns: - - "drupal/core*" - localgov: - patterns: - - "localgovdrupal/*" - - # Python dependencies (Lambda layers) - - package-ecosystem: "pip" - directory: "/cloudformation/layers/uk-data-generator" - schedule: - interval: "weekly" - cooldown: - default-days: 7 - open-pull-requests-limit: 5 - - # Docker dependencies - - package-ecosystem: "docker" - directory: "/cloudformation/scenarios/localgov-drupal/docker" - schedule: - interval: "weekly" - cooldown: - default-days: 7 - open-pull-requests-limit: 3 - - # GitHub Actions - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - cooldown: - default-days: 7 - open-pull-requests-limit: 5 - groups: - github-actions: - patterns: - - "*" diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml new file mode 100644 index 00000000..a672d3e5 --- /dev/null +++ b/.github/workflows/renovate.yml @@ -0,0 +1,61 @@ +name: Renovate + +# Self-hosted Renovate via renovatebot/github-action. Phase 6 of the +# scenario-regression smoke-pack tech-spec. Replaces .github/dependabot.yml +# (deleted in this PR per ADR-2) with the unified bot. +# +# Cadence: twice daily. The cold-start cost is non-trivial (~2-3 min full +# scan + per-package resolution) so 4×/day would burn CI minutes without +# proportional value. workflow_dispatch lets a maintainer trigger ad-hoc. +# +# Action pin: digest, not tag. The spec's pinning strategy is "every pin +# must carry a Renovate-trackable tag alongside the digest." The digest +# below tracks v46.1.14 of renovatebot/github-action. Renovate's +# github-actions packageRule (in renovate.json) pinDigests=true keeps +# this current. + +on: + schedule: + - cron: '0 6,18 * * *' # 06:00 and 18:00 UTC daily + workflow_dispatch: + inputs: + logLevel: + description: 'Log level (debug for verbose)' + required: false + default: 'info' + type: choice + options: + - info + - debug + +permissions: + contents: read + # Renovate writes via the PAT (RENOVATE_TOKEN), NOT GITHUB_TOKEN. Keeping + # GITHUB_TOKEN's permissions tight prevents accidental scope creep. + +concurrency: + group: renovate + cancel-in-progress: false + +jobs: + renovate: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + + - name: Run Renovate + uses: renovatebot/github-action@693b9ef15eec82123529a37c782242f091365961 # v46.1.14 + with: + # Fine-grained PAT scoped repo:read+write on co-cddo/ndx_try_aws_scenarios only. + # Minted by the operator per docs/smoke-test-account-setup.md → + # Operational Notes → RENOVATE_TOKEN rotation. + token: ${{ secrets.RENOVATE_TOKEN }} + configurationFile: renovate.json + env: + LOG_LEVEL: ${{ inputs.logLevel || 'info' }} + RENOVATE_PLATFORM: github + RENOVATE_REPOSITORIES: '["co-cddo/ndx_try_aws_scenarios"]' + # Keep Renovate's onboarding off; renovate.json is the committed config. + RENOVATE_ONBOARDING: 'false' + RENOVATE_REQUIRE_CONFIG: 'required' diff --git a/cloudformation/scenarios/bops-planning/docker/bops/Dockerfile b/cloudformation/scenarios/bops-planning/docker/bops/Dockerfile index 10161395..970dfe2f 100644 --- a/cloudformation/scenarios/bops-planning/docker/bops/Dockerfile +++ b/cloudformation/scenarios/bops-planning/docker/bops/Dockerfile @@ -17,4 +17,4 @@ # cp scripts/seed_sample_data.rb bops-src/scripts/ # cp scripts/seed-entrypoint.sh bops-src/scripts/ # cp entrypoint.sh bops-src/ -# docker build -f bops-src/Dockerfile.production -t bops:latest bops-src/ +# docker build -f bops-src/Dockerfile.production -t bops-local bops-src/ diff --git a/cloudformation/scenarios/digital-planning-register/cdk/lib/digital-planning-register-stack.ts b/cloudformation/scenarios/digital-planning-register/cdk/lib/digital-planning-register-stack.ts index c51cc37e..52dd08ba 100644 --- a/cloudformation/scenarios/digital-planning-register/cdk/lib/digital-planning-register-stack.ts +++ b/cloudformation/scenarios/digital-planning-register/cdk/lib/digital-planning-register-stack.ts @@ -61,7 +61,7 @@ export class DigitalPlanningRegisterStack extends cdk.Stack { // CloudFormation parameter for Docker image URI const imageUriParam = new cdk.CfnParameter(this, 'ImageUri', { type: 'String', - default: 'ghcr.io/co-cddo/ndx_try_aws_scenarios-dpr:latest', + default: 'ghcr.io/co-cddo/ndx_try_aws_scenarios-dpr:sha-33e9e9f@sha256:775db3c01e2cb01302078b1e2e9129423016ec8c4dc2000f3c35066e2912de35', description: 'Docker image URI for the Digital Planning Register container', }); diff --git a/cloudformation/scenarios/fixmystreet/cdk/lib/constructs/compute.ts b/cloudformation/scenarios/fixmystreet/cdk/lib/constructs/compute.ts index 2814a6b5..063c6c97 100644 --- a/cloudformation/scenarios/fixmystreet/cdk/lib/constructs/compute.ts +++ b/cloudformation/scenarios/fixmystreet/cdk/lib/constructs/compute.ts @@ -94,7 +94,7 @@ export class ComputeConstruct extends Construct { // Main FixMyStreet container (Perl/Catalyst app on port 9000) const fmsContainer = this.taskDefinition.addContainer('fixmystreet', { - image: ecs.ContainerImage.fromRegistry('ghcr.io/co-cddo/ndx_try_aws_scenarios-fixmystreet:latest'), + image: ecs.ContainerImage.fromRegistry('ghcr.io/co-cddo/ndx_try_aws_scenarios-fixmystreet:sha-be035a6@sha256:863c3e7dded6d2132663b9e46725bc4f46e934c8ce86b3977a13ade45d986e94'), logging: ecs.LogDrivers.awsLogs({ logGroup: this.logGroup, streamPrefix: 'fms', diff --git a/cloudformation/scenarios/localgov-drupal/cdk/lib/constructs/compute.ts b/cloudformation/scenarios/localgov-drupal/cdk/lib/constructs/compute.ts index ac14943a..74c738eb 100644 --- a/cloudformation/scenarios/localgov-drupal/cdk/lib/constructs/compute.ts +++ b/cloudformation/scenarios/localgov-drupal/cdk/lib/constructs/compute.ts @@ -272,7 +272,7 @@ export class ComputeConstruct extends Construct { // Add container - pull from GitHub Container Registry const container = taskDefinition.addContainer('drupal', { - image: ecs.ContainerImage.fromRegistry('ghcr.io/co-cddo/ndx_try_aws_scenarios-localgov_drupal:latest'), + image: ecs.ContainerImage.fromRegistry('ghcr.io/co-cddo/ndx_try_aws_scenarios-localgov_drupal:sha-5801fb7@sha256:e91947e3eebc50d408921367069d6e4046a6e61f94521e19c6b0b55a5773e5d0'), logging: ecs.LogDrivers.awsLogs({ logGroup: this.logGroup, streamPrefix: 'drupal', diff --git a/cloudformation/scenarios/localgov-drupal/template.yaml b/cloudformation/scenarios/localgov-drupal/template.yaml index 13828cd7..92ec6381 100644 --- a/cloudformation/scenarios/localgov-drupal/template.yaml +++ b/cloudformation/scenarios/localgov-drupal/template.yaml @@ -830,7 +830,7 @@ Resources: Retries: 5 StartPeriod: 300 Timeout: 10 - Image: ghcr.io/co-cddo/ndx_try_aws_scenarios-localgov_drupal:latest + Image: ghcr.io/co-cddo/ndx_try_aws_scenarios-localgov_drupal:sha-5801fb7@sha256:e91947e3eebc50d408921367069d6e4046a6e61f94521e19c6b0b55a5773e5d0 LogConfiguration: LogDriver: awslogs Options: diff --git a/cloudformation/scenarios/minute/cdk/lib/constructs/compute.ts b/cloudformation/scenarios/minute/cdk/lib/constructs/compute.ts index df58960f..1947c239 100644 --- a/cloudformation/scenarios/minute/cdk/lib/constructs/compute.ts +++ b/cloudformation/scenarios/minute/cdk/lib/constructs/compute.ts @@ -11,10 +11,12 @@ import * as servicediscovery from 'aws-cdk-lib/aws-servicediscovery'; import * as sqs from 'aws-cdk-lib/aws-sqs'; import { Construct } from 'constructs'; -// GHCR public images (built by .github/workflows/docker-build-minute.yml) -const FRONTEND_IMAGE = 'ghcr.io/co-cddo/ndx_try_aws_scenarios-minute_frontend:latest'; -const BACKEND_IMAGE = 'ghcr.io/co-cddo/ndx_try_aws_scenarios-minute_backend:latest'; -const WORKER_IMAGE = 'ghcr.io/co-cddo/ndx_try_aws_scenarios-minute_worker:latest'; +// GHCR public images (built by .github/workflows/docker-build-minute.yml). +// Pins follow the spec's "own GHCR" pattern: :sha-<7chars>@sha256:. +// Renovate tracks both via the regex in renovate.json. +const FRONTEND_IMAGE = 'ghcr.io/co-cddo/ndx_try_aws_scenarios-minute_frontend:sha-5d3d423@sha256:0cfbf3bca86f2360935765dc5ae33e9cbcc88d96ad2d58fd5c9d0a5b99862abf'; +const BACKEND_IMAGE = 'ghcr.io/co-cddo/ndx_try_aws_scenarios-minute_backend:sha-5d3d423@sha256:0830ab1fe636764380c0eb2ea56530abfff6658a694f3550f9dda2eddb48517b'; +const WORKER_IMAGE = 'ghcr.io/co-cddo/ndx_try_aws_scenarios-minute_worker:sha-5d3d423@sha256:13d7800495c7268cd75170649025e6a7f98bf12cdd2e87cbdab5ddbef5d76a65'; export interface ComputeConstructProps { readonly vpc: ec2.IVpc; diff --git a/cloudformation/scenarios/minute/template.json b/cloudformation/scenarios/minute/template.json deleted file mode 100644 index 8df6e3fa..00000000 --- a/cloudformation/scenarios/minute/template.json +++ /dev/null @@ -1 +0,0 @@ -{"Description":"Minute AI - Meeting Transcription & Minuting on AWS","Resources":{"AppRegistryApplication":{"Type":"AWS::ServiceCatalogAppRegistry::Application","Properties":{"Description":"NDX:Try - Minute AI Meeting Transcription & Minuting","Name":{"Fn::Join":["",["NDXTry_Minute_",{"Ref":"AWS::AccountId"}]]},"Tags":{"Project":"ndx-try-aws-scenarios","Scenario":"minute"}},"Metadata":{"aws:cdk:path":"MinuteStack/AppRegistryApplication"}},"AppRegistryAssociation":{"Type":"AWS::ServiceCatalogAppRegistry::ResourceAssociation","Properties":{"Application":{"Fn::GetAtt":["AppRegistryApplication","Id"]},"Resource":{"Ref":"AWS::StackId"},"ResourceType":"CFN_STACK"},"Metadata":{"aws:cdk:path":"MinuteStack/AppRegistryAssociation"}},"NetworkingVpc6B5E6F44":{"Type":"AWS::EC2::VPC","Properties":{"CidrBlock":"10.0.0.0/16","EnableDnsHostnames":true,"EnableDnsSupport":true,"InstanceTenancy":"default","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Name","Value":"NdxMinute-VPC"},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/Resource"}},"NetworkingVpcPublicSubnet1Subnet918289EE":{"Type":"AWS::EC2::Subnet","Properties":{"AvailabilityZone":{"Fn::Select":[0,{"Fn::GetAZs":""}]},"CidrBlock":"10.0.0.0/24","MapPublicIpOnLaunch":true,"Tags":[{"Key":"aws-cdk:subnet-name","Value":"Public"},{"Key":"aws-cdk:subnet-type","Value":"Public"},{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Name","Value":"MinuteStack/Networking/Vpc/PublicSubnet1"},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/PublicSubnet1/Subnet"}},"NetworkingVpcPublicSubnet1RouteTable8FB3C18A":{"Type":"AWS::EC2::RouteTable","Properties":{"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Name","Value":"MinuteStack/Networking/Vpc/PublicSubnet1"},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/PublicSubnet1/RouteTable"}},"NetworkingVpcPublicSubnet1RouteTableAssociationD13830EA":{"Type":"AWS::EC2::SubnetRouteTableAssociation","Properties":{"RouteTableId":{"Ref":"NetworkingVpcPublicSubnet1RouteTable8FB3C18A"},"SubnetId":{"Ref":"NetworkingVpcPublicSubnet1Subnet918289EE"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/PublicSubnet1/RouteTableAssociation"}},"NetworkingVpcPublicSubnet1DefaultRoute80C01FA6":{"Type":"AWS::EC2::Route","Properties":{"DestinationCidrBlock":"0.0.0.0/0","GatewayId":{"Ref":"NetworkingVpcIGW21218DAB"},"RouteTableId":{"Ref":"NetworkingVpcPublicSubnet1RouteTable8FB3C18A"}},"DependsOn":["NetworkingVpcVPCGW12E561D8"],"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/PublicSubnet1/DefaultRoute"}},"NetworkingVpcPublicSubnet2Subnet9D9E5AFB":{"Type":"AWS::EC2::Subnet","Properties":{"AvailabilityZone":{"Fn::Select":[1,{"Fn::GetAZs":""}]},"CidrBlock":"10.0.1.0/24","MapPublicIpOnLaunch":true,"Tags":[{"Key":"aws-cdk:subnet-name","Value":"Public"},{"Key":"aws-cdk:subnet-type","Value":"Public"},{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Name","Value":"MinuteStack/Networking/Vpc/PublicSubnet2"},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/PublicSubnet2/Subnet"}},"NetworkingVpcPublicSubnet2RouteTable22886677":{"Type":"AWS::EC2::RouteTable","Properties":{"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Name","Value":"MinuteStack/Networking/Vpc/PublicSubnet2"},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/PublicSubnet2/RouteTable"}},"NetworkingVpcPublicSubnet2RouteTableAssociation2D4CEA06":{"Type":"AWS::EC2::SubnetRouteTableAssociation","Properties":{"RouteTableId":{"Ref":"NetworkingVpcPublicSubnet2RouteTable22886677"},"SubnetId":{"Ref":"NetworkingVpcPublicSubnet2Subnet9D9E5AFB"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/PublicSubnet2/RouteTableAssociation"}},"NetworkingVpcPublicSubnet2DefaultRouteDF98F60F":{"Type":"AWS::EC2::Route","Properties":{"DestinationCidrBlock":"0.0.0.0/0","GatewayId":{"Ref":"NetworkingVpcIGW21218DAB"},"RouteTableId":{"Ref":"NetworkingVpcPublicSubnet2RouteTable22886677"}},"DependsOn":["NetworkingVpcVPCGW12E561D8"],"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/PublicSubnet2/DefaultRoute"}},"NetworkingVpcIGW21218DAB":{"Type":"AWS::EC2::InternetGateway","Properties":{"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Name","Value":"NdxMinute-VPC"},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/IGW"}},"NetworkingVpcVPCGW12E561D8":{"Type":"AWS::EC2::VPCGatewayAttachment","Properties":{"InternetGatewayId":{"Ref":"NetworkingVpcIGW21218DAB"},"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/Vpc/VPCGW"}},"NetworkingAlbSecurityGroup5ADC578E":{"Type":"AWS::EC2::SecurityGroup","Properties":{"GroupDescription":"ALB security group for Minute AI","GroupName":"NdxMinute-ALB-SG","SecurityGroupIngress":[{"CidrIp":"0.0.0.0/0","Description":"Allow HTTP from internet","FromPort":80,"IpProtocol":"tcp","ToPort":80}],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/AlbSecurityGroup/Resource"}},"NetworkingAlbSecurityGrouptoMinuteStackNetworkingFargateSecurityGroup8A63491E8081495CEBC6":{"Type":"AWS::EC2::SecurityGroupEgress","Properties":{"Description":"Allow HTTP to frontend tasks","DestinationSecurityGroupId":{"Fn::GetAtt":["NetworkingFargateSecurityGroupFC850E44","GroupId"]},"FromPort":8081,"GroupId":{"Fn::GetAtt":["NetworkingAlbSecurityGroup5ADC578E","GroupId"]},"IpProtocol":"tcp","ToPort":8081},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/AlbSecurityGroup/to MinuteStackNetworkingFargateSecurityGroup8A63491E:8081"}},"NetworkingFargateSecurityGroupFC850E44":{"Type":"AWS::EC2::SecurityGroup","Properties":{"GroupDescription":"Fargate task security group for Minute AI","GroupName":"NdxMinute-Fargate-SG","SecurityGroupEgress":[{"CidrIp":"0.0.0.0/0","Description":"Allow all outbound traffic by default","IpProtocol":"-1"}],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/FargateSecurityGroup/Resource"}},"NetworkingFargateSecurityGroupfromMinuteStackNetworkingAlbSecurityGroup05BCC2D38081D336DF09":{"Type":"AWS::EC2::SecurityGroupIngress","Properties":{"Description":"Allow HTTP from ALB to frontend","FromPort":8081,"GroupId":{"Fn::GetAtt":["NetworkingFargateSecurityGroupFC850E44","GroupId"]},"IpProtocol":"tcp","SourceSecurityGroupId":{"Fn::GetAtt":["NetworkingAlbSecurityGroup5ADC578E","GroupId"]},"ToPort":8081},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/FargateSecurityGroup/from MinuteStackNetworkingAlbSecurityGroup05BCC2D3:8081"}},"NetworkingFargateSecurityGroupfromMinuteStackNetworkingFargateSecurityGroup8A63491E808059084FC6":{"Type":"AWS::EC2::SecurityGroupIngress","Properties":{"Description":"Allow frontend to backend via Cloud Map","FromPort":8080,"GroupId":{"Fn::GetAtt":["NetworkingFargateSecurityGroupFC850E44","GroupId"]},"IpProtocol":"tcp","SourceSecurityGroupId":{"Fn::GetAtt":["NetworkingFargateSecurityGroupFC850E44","GroupId"]},"ToPort":8080},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/FargateSecurityGroup/from MinuteStackNetworkingFargateSecurityGroup8A63491E:8080"}},"NetworkingAuroraSecurityGroupDB53DF94":{"Type":"AWS::EC2::SecurityGroup","Properties":{"GroupDescription":"Aurora PostgreSQL security group for Minute AI","GroupName":"NdxMinute-Aurora-SG","SecurityGroupEgress":[{"CidrIp":"255.255.255.255/32","Description":"Disallow all traffic","FromPort":252,"IpProtocol":"icmp","ToPort":86}],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/AuroraSecurityGroup/Resource"}},"NetworkingAuroraSecurityGroupfromMinuteStackNetworkingFargateSecurityGroup8A63491E5432509FB9ED":{"Type":"AWS::EC2::SecurityGroupIngress","Properties":{"Description":"Allow PostgreSQL from Fargate tasks","FromPort":5432,"GroupId":{"Fn::GetAtt":["NetworkingAuroraSecurityGroupDB53DF94","GroupId"]},"IpProtocol":"tcp","SourceSecurityGroupId":{"Fn::GetAtt":["NetworkingFargateSecurityGroupFC850E44","GroupId"]},"ToPort":5432},"Metadata":{"aws:cdk:path":"MinuteStack/Networking/AuroraSecurityGroup/from MinuteStackNetworkingFargateSecurityGroup8A63491E:5432"}},"DatabaseDbSecret1098DC6E":{"Type":"AWS::SecretsManager::Secret","Properties":{"Description":"Database credentials for Minute AI","GenerateSecretString":{"ExcludePunctuation":true,"GenerateStringKey":"password","PasswordLength":32,"SecretStringTemplate":"{\"username\":\"minuteadmin\"}"},"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Database/DbSecret/Resource"}},"DatabaseDbSecretAttachment34026B56":{"Type":"AWS::SecretsManager::SecretTargetAttachment","Properties":{"SecretId":{"Ref":"DatabaseDbSecret1098DC6E"},"TargetId":{"Ref":"DatabaseAuroraCF3B5693"},"TargetType":"AWS::RDS::DBCluster"},"Metadata":{"aws:cdk:path":"MinuteStack/Database/DbSecret/Attachment/Resource"}},"DatabaseAuroraSubnetsC2098A6E":{"Type":"AWS::RDS::DBSubnetGroup","Properties":{"DBSubnetGroupDescription":"Subnets for Aurora database","SubnetIds":[{"Ref":"NetworkingVpcPublicSubnet1Subnet918289EE"},{"Ref":"NetworkingVpcPublicSubnet2Subnet9D9E5AFB"}],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Database/Aurora/Subnets/Default"}},"DatabaseAuroraCF3B5693":{"Type":"AWS::RDS::DBCluster","Properties":{"BackupRetentionPeriod":1,"CopyTagsToSnapshot":true,"DBClusterParameterGroupName":"default.aurora-postgresql16","DBSubnetGroupName":{"Ref":"DatabaseAuroraSubnetsC2098A6E"},"DatabaseName":"minute_db","DeletionProtection":false,"Engine":"aurora-postgresql","EngineVersion":"16.4","MasterUserPassword":{"Fn::Join":["",["{{resolve:secretsmanager:",{"Ref":"DatabaseDbSecret1098DC6E"},":SecretString:password::}}"]]},"MasterUsername":{"Fn::Join":["",["{{resolve:secretsmanager:",{"Ref":"DatabaseDbSecret1098DC6E"},":SecretString:username::}}"]]},"Port":5432,"ServerlessV2ScalingConfiguration":{"MaxCapacity":2,"MinCapacity":0.5},"StorageEncrypted":true,"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VpcSecurityGroupIds":[{"Fn::GetAtt":["NetworkingAuroraSecurityGroupDB53DF94","GroupId"]}]},"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Database/Aurora/Resource"}},"DatabaseAurorawriter2449CF28":{"Type":"AWS::RDS::DBInstance","Properties":{"DBClusterIdentifier":{"Ref":"DatabaseAuroraCF3B5693"},"DBInstanceClass":"db.serverless","Engine":"aurora-postgresql","PromotionTier":0,"PubliclyAccessible":false,"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"DependsOn":["NetworkingVpcPublicSubnet1DefaultRoute80C01FA6","NetworkingVpcPublicSubnet1RouteTableAssociationD13830EA","NetworkingVpcPublicSubnet2DefaultRouteDF98F60F","NetworkingVpcPublicSubnet2RouteTableAssociation2D4CEA06"],"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Database/Aurora/writer/Resource"}},"QueuesTranscriptionDLQ6D36226D":{"Type":"AWS::SQS::Queue","Properties":{"MessageRetentionPeriod":1209600,"QueueName":"minute-transcription-dlq","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Queues/TranscriptionDLQ/Resource"}},"QueuesTranscriptionQueueA02E7327":{"Type":"AWS::SQS::Queue","Properties":{"MessageRetentionPeriod":345600,"QueueName":"minute-transcription-queue","RedrivePolicy":{"deadLetterTargetArn":{"Fn::GetAtt":["QueuesTranscriptionDLQ6D36226D","Arn"]},"maxReceiveCount":4},"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VisibilityTimeout":1800},"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Queues/TranscriptionQueue/Resource"}},"QueuesLlmDLQ37A16FA3":{"Type":"AWS::SQS::Queue","Properties":{"MessageRetentionPeriod":1209600,"QueueName":"minute-llm-dlq","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Queues/LlmDLQ/Resource"}},"QueuesLlmQueueE3526008":{"Type":"AWS::SQS::Queue","Properties":{"MessageRetentionPeriod":345600,"QueueName":"minute-llm-queue","RedrivePolicy":{"deadLetterTargetArn":{"Fn::GetAtt":["QueuesLlmDLQ37A16FA3","Arn"]},"maxReceiveCount":4},"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"VisibilityTimeout":1800},"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Queues/LlmQueue/Resource"}},"StorageDataBucketB1B922FA":{"Type":"AWS::S3::Bucket","Properties":{"BucketEncryption":{"ServerSideEncryptionConfiguration":[{"ServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]},"CorsConfiguration":{"CorsRules":[{"AllowedHeaders":["*"],"AllowedMethods":["GET","PUT","POST","DELETE"],"AllowedOrigins":["*"]}]},"PublicAccessBlockConfiguration":{"BlockPublicAcls":true,"BlockPublicPolicy":true,"IgnorePublicAcls":true,"RestrictPublicBuckets":true},"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Storage/DataBucket/Resource"}},"StorageDataBucketPolicyC997B69E":{"Type":"AWS::S3::BucketPolicy","Properties":{"Bucket":{"Ref":"StorageDataBucketB1B922FA"},"PolicyDocument":{"Statement":[{"Action":"s3:*","Condition":{"Bool":{"aws:SecureTransport":"false"}},"Effect":"Deny","Principal":{"AWS":"*"},"Resource":[{"Fn::GetAtt":["StorageDataBucketB1B922FA","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["StorageDataBucketB1B922FA","Arn"]},"/*"]]}]},{"Action":["s3:GetObject","s3:PutObject","s3:DeleteObject"],"Effect":"Allow","Principal":{"Service":"transcribe.amazonaws.com"},"Resource":{"Fn::Join":["",[{"Fn::GetAtt":["StorageDataBucketB1B922FA","Arn"]},"/*"]]}}],"Version":"2012-10-17"}},"Metadata":{"aws:cdk:path":"MinuteStack/Storage/DataBucket/Policy/Resource"}},"ComputeCluster4F8E5F81":{"Type":"AWS::ECS::Cluster","Properties":{"ClusterName":"NdxMinute","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/Cluster/Resource"}},"ComputeNamespace07358158":{"Type":"AWS::ServiceDiscovery::PrivateDnsNamespace","Properties":{"Name":"minute-internal","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"Vpc":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/Namespace/Resource"}},"ComputeLogGroup1A40385B":{"Type":"AWS::Logs::LogGroup","Properties":{"LogGroupName":"/ndx-minute","RetentionInDays":7,"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"UpdateReplacePolicy":"Delete","DeletionPolicy":"Delete","Metadata":{"aws:cdk:path":"MinuteStack/Compute/LogGroup/Resource"}},"ComputeExecutionRoleCE43D454":{"Type":"AWS::IAM::Role","Properties":{"AssumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"ecs-tasks.amazonaws.com"}}],"Version":"2012-10-17"},"ManagedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]]}],"RoleName":"InnovationSandbox-ndx-minute-exec","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/ExecutionRole/Resource"}},"ComputeExecutionRoleDefaultPolicy29213E53":{"Type":"AWS::IAM::Policy","Properties":{"PolicyDocument":{"Statement":[{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":{"Ref":"DatabaseDbSecret1098DC6E"}},{"Action":["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":ecr:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":repository/minute-frontend"]]}},{"Action":"ecr:GetAuthorizationToken","Effect":"Allow","Resource":"*"},{"Action":["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":ecr:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":repository/minute-backend"]]}},{"Action":["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":ecr:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":repository/minute-worker"]]}},{"Action":["logs:CreateLogStream","logs:PutLogEvents"],"Effect":"Allow","Resource":{"Fn::GetAtt":["ComputeLogGroup1A40385B","Arn"]}}],"Version":"2012-10-17"},"PolicyName":"ComputeExecutionRoleDefaultPolicy29213E53","Roles":[{"Ref":"ComputeExecutionRoleCE43D454"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/ExecutionRole/DefaultPolicy/Resource"}},"ComputeBackendTaskRole2A6DA82D":{"Type":"AWS::IAM::Role","Properties":{"AssumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"ecs-tasks.amazonaws.com"}}],"Version":"2012-10-17"},"RoleName":"InnovationSandbox-ndx-minute-backend-task","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/BackendTaskRole/Resource"}},"ComputeBackendTaskRoleDefaultPolicyBF2D54F3":{"Type":"AWS::IAM::Policy","Properties":{"PolicyDocument":{"Statement":[{"Action":["s3:GetObject*","s3:GetBucket*","s3:List*","s3:DeleteObject*","s3:PutObject","s3:PutObjectLegalHold","s3:PutObjectRetention","s3:PutObjectTagging","s3:PutObjectVersionTagging","s3:Abort*"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["StorageDataBucketB1B922FA","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["StorageDataBucketB1B922FA","Arn"]},"/*"]]}]},{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesTranscriptionQueueA02E7327","Arn"]}},{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesTranscriptionDLQ6D36226D","Arn"]}},{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesLlmQueueE3526008","Arn"]}},{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesLlmDLQ37A16FA3","Arn"]}},{"Action":["logs:CreateLogStream","logs:PutLogEvents"],"Effect":"Allow","Resource":{"Fn::GetAtt":["ComputeLogGroup1A40385B","Arn"]}},{"Action":["ssmmessages:CreateControlChannel","ssmmessages:CreateDataChannel","ssmmessages:OpenControlChannel","ssmmessages:OpenDataChannel"],"Effect":"Allow","Resource":"*"},{"Action":"logs:DescribeLogGroups","Effect":"Allow","Resource":"*"},{"Action":["logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],"Effect":"Allow","Resource":"*"}],"Version":"2012-10-17"},"PolicyName":"ComputeBackendTaskRoleDefaultPolicyBF2D54F3","Roles":[{"Ref":"ComputeBackendTaskRole2A6DA82D"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/BackendTaskRole/DefaultPolicy/Resource"}},"ComputeWorkerTaskRole3135DAE0":{"Type":"AWS::IAM::Role","Properties":{"AssumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"ecs-tasks.amazonaws.com"}}],"Version":"2012-10-17"},"RoleName":"InnovationSandbox-ndx-minute-worker-task","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/WorkerTaskRole/Resource"}},"ComputeWorkerTaskRoleDefaultPolicyA8BEE6C7":{"Type":"AWS::IAM::Policy","Properties":{"PolicyDocument":{"Statement":[{"Action":["s3:GetObject*","s3:GetBucket*","s3:List*","s3:DeleteObject*","s3:PutObject","s3:PutObjectLegalHold","s3:PutObjectRetention","s3:PutObjectTagging","s3:PutObjectVersionTagging","s3:Abort*"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["StorageDataBucketB1B922FA","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["StorageDataBucketB1B922FA","Arn"]},"/*"]]}]},{"Action":["sqs:ReceiveMessage","sqs:ChangeMessageVisibility","sqs:GetQueueUrl","sqs:DeleteMessage","sqs:GetQueueAttributes"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesTranscriptionQueueA02E7327","Arn"]}},{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesTranscriptionQueueA02E7327","Arn"]}},{"Action":["sqs:ReceiveMessage","sqs:ChangeMessageVisibility","sqs:GetQueueUrl","sqs:DeleteMessage","sqs:GetQueueAttributes"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesLlmQueueE3526008","Arn"]}},{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesLlmQueueE3526008","Arn"]}},{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesTranscriptionDLQ6D36226D","Arn"]}},{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["QueuesLlmDLQ37A16FA3","Arn"]}},{"Action":["bedrock:InvokeModel","bedrock:InvokeModelWithResponseStream","bedrock:Converse","bedrock:ConverseStream"],"Effect":"Allow","Resource":["arn:aws:bedrock:*::foundation-model/anthropic.*","arn:aws:bedrock:*::foundation-model/amazon.nova-*"]},{"Action":["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],"Effect":"Allow","Resource":"*"},{"Action":["logs:CreateLogStream","logs:PutLogEvents"],"Effect":"Allow","Resource":{"Fn::GetAtt":["ComputeLogGroup1A40385B","Arn"]}},{"Action":["ssmmessages:CreateControlChannel","ssmmessages:CreateDataChannel","ssmmessages:OpenControlChannel","ssmmessages:OpenDataChannel"],"Effect":"Allow","Resource":"*"},{"Action":"logs:DescribeLogGroups","Effect":"Allow","Resource":"*"},{"Action":["logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],"Effect":"Allow","Resource":"*"}],"Version":"2012-10-17"},"PolicyName":"ComputeWorkerTaskRoleDefaultPolicyA8BEE6C7","Roles":[{"Ref":"ComputeWorkerTaskRole3135DAE0"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/WorkerTaskRole/DefaultPolicy/Resource"}},"ComputeFrontendTaskRole8DA2A7B1":{"Type":"AWS::IAM::Role","Properties":{"AssumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"ecs-tasks.amazonaws.com"}}],"Version":"2012-10-17"},"RoleName":"InnovationSandbox-ndx-minute-frontend-task","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/FrontendTaskRole/Resource"}},"ComputeFrontendTaskRoleDefaultPolicy66A31476":{"Type":"AWS::IAM::Policy","Properties":{"PolicyDocument":{"Statement":[{"Action":["logs:CreateLogStream","logs:PutLogEvents"],"Effect":"Allow","Resource":{"Fn::GetAtt":["ComputeLogGroup1A40385B","Arn"]}},{"Action":["ssmmessages:CreateControlChannel","ssmmessages:CreateDataChannel","ssmmessages:OpenControlChannel","ssmmessages:OpenDataChannel"],"Effect":"Allow","Resource":"*"},{"Action":"logs:DescribeLogGroups","Effect":"Allow","Resource":"*"},{"Action":["logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],"Effect":"Allow","Resource":"*"}],"Version":"2012-10-17"},"PolicyName":"ComputeFrontendTaskRoleDefaultPolicy66A31476","Roles":[{"Ref":"ComputeFrontendTaskRole8DA2A7B1"}]},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/FrontendTaskRole/DefaultPolicy/Resource"}},"ComputeBackendTaskDef456FE261":{"Type":"AWS::ECS::TaskDefinition","Properties":{"ContainerDefinitions":[{"Environment":[{"Name":"ENVIRONMENT","Value":"local"},{"Name":"POSTGRES_HOST","Value":{"Fn::GetAtt":["DatabaseAuroraCF3B5693","Endpoint.Address"]}},{"Name":"POSTGRES_PORT","Value":{"Fn::GetAtt":["DatabaseAuroraCF3B5693","Endpoint.Port"]}},{"Name":"POSTGRES_DB","Value":"minute_db"},{"Name":"POSTGRES_USER","Value":{"Fn::Join":["",["{{resolve:secretsmanager:",{"Ref":"DatabaseDbSecret1098DC6E"},":SecretString:username::}}"]]}},{"Name":"POSTGRES_PASSWORD","Value":{"Fn::Join":["",["{{resolve:secretsmanager:",{"Ref":"DatabaseDbSecret1098DC6E"},":SecretString:password::}}"]]}},{"Name":"DATA_S3_BUCKET","Value":{"Ref":"StorageDataBucketB1B922FA"}},{"Name":"TRANSCRIPTION_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesTranscriptionQueueA02E7327","QueueName"]}},{"Name":"TRANSCRIPTION_DEADLETTER_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesTranscriptionDLQ6D36226D","QueueName"]}},{"Name":"LLM_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesLlmQueueE3526008","QueueName"]}},{"Name":"LLM_DEADLETTER_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesLlmDLQ37A16FA3","QueueName"]}},{"Name":"QUEUE_SERVICE_NAME","Value":"sqs"},{"Name":"STORAGE_SERVICE_NAME","Value":"s3"},{"Name":"AWS_DEFAULT_REGION","Value":{"Ref":"AWS::Region"}},{"Name":"AWS_REGION","Value":{"Ref":"AWS::Region"}},{"Name":"AWS_ACCOUNT_ID","Value":{"Ref":"AWS::AccountId"}},{"Name":"USE_LOCALSTACK","Value":"false"},{"Name":"PORT","Value":"8080"},{"Name":"REPO","Value":"minute"}],"Essential":true,"HealthCheck":{"Command":["CMD-SHELL","curl -f http://localhost:8080/healthcheck || exit 1"],"Interval":30,"Retries":5,"StartPeriod":300,"Timeout":10},"Image":{"Fn::Join":["",[{"Ref":"AWS::AccountId"},".dkr.ecr.",{"Ref":"AWS::Region"},".",{"Ref":"AWS::URLSuffix"},"/minute-backend:latest"]]},"LogConfiguration":{"LogDriver":"awslogs","Options":{"awslogs-group":{"Ref":"ComputeLogGroup1A40385B"},"awslogs-stream-prefix":"backend","awslogs-region":{"Ref":"AWS::Region"}}},"Name":"backend","PortMappings":[{"ContainerPort":8080,"Protocol":"tcp"}]}],"Cpu":"1024","ExecutionRoleArn":{"Fn::GetAtt":["ComputeExecutionRoleCE43D454","Arn"]},"Family":"MinuteStackComputeBackendTaskDef545B1441","Memory":"2048","NetworkMode":"awsvpc","RequiresCompatibilities":["FARGATE"],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"TaskRoleArn":{"Fn::GetAtt":["ComputeBackendTaskRole2A6DA82D","Arn"]}},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/BackendTaskDef/Resource"}},"ComputeBackendService32A5EB00":{"Type":"AWS::ECS::Service","Properties":{"Cluster":{"Ref":"ComputeCluster4F8E5F81"},"DeploymentConfiguration":{"Alarms":{"AlarmNames":[],"Enable":false,"Rollback":false},"MaximumPercent":200,"MinimumHealthyPercent":50},"DesiredCount":1,"EnableECSManagedTags":false,"EnableExecuteCommand":true,"HealthCheckGracePeriodSeconds":900,"LaunchType":"FARGATE","NetworkConfiguration":{"AwsvpcConfiguration":{"AssignPublicIp":"ENABLED","SecurityGroups":[{"Fn::GetAtt":["NetworkingFargateSecurityGroupFC850E44","GroupId"]}],"Subnets":[{"Ref":"NetworkingVpcPublicSubnet1Subnet918289EE"},{"Ref":"NetworkingVpcPublicSubnet2Subnet9D9E5AFB"}]}},"ServiceName":"NdxMinute-Backend","ServiceRegistries":[{"RegistryArn":{"Fn::GetAtt":["ComputeBackendServiceCloudmapService4A0DACEB","Arn"]}}],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"TaskDefinition":{"Ref":"ComputeBackendTaskDef456FE261"}},"DependsOn":["ComputeBackendTaskRoleDefaultPolicyBF2D54F3","ComputeBackendTaskRole2A6DA82D"],"Metadata":{"aws:cdk:path":"MinuteStack/Compute/BackendService/Service"}},"ComputeBackendServiceCloudmapService4A0DACEB":{"Type":"AWS::ServiceDiscovery::Service","Properties":{"DnsConfig":{"DnsRecords":[{"TTL":60,"Type":"A"}],"NamespaceId":{"Fn::GetAtt":["ComputeNamespace07358158","Id"]},"RoutingPolicy":"MULTIVALUE"},"HealthCheckCustomConfig":{"FailureThreshold":1},"Name":"minute-backend","NamespaceId":{"Fn::GetAtt":["ComputeNamespace07358158","Id"]},"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"DependsOn":["ComputeBackendTaskRoleDefaultPolicyBF2D54F3","ComputeBackendTaskRole2A6DA82D"],"Metadata":{"aws:cdk:path":"MinuteStack/Compute/BackendService/CloudmapService/Resource"}},"ComputeWorkerTaskDef5D93855B":{"Type":"AWS::ECS::TaskDefinition","Properties":{"ContainerDefinitions":[{"Environment":[{"Name":"ENVIRONMENT","Value":"local"},{"Name":"POSTGRES_HOST","Value":{"Fn::GetAtt":["DatabaseAuroraCF3B5693","Endpoint.Address"]}},{"Name":"POSTGRES_PORT","Value":{"Fn::GetAtt":["DatabaseAuroraCF3B5693","Endpoint.Port"]}},{"Name":"POSTGRES_DB","Value":"minute_db"},{"Name":"POSTGRES_USER","Value":{"Fn::Join":["",["{{resolve:secretsmanager:",{"Ref":"DatabaseDbSecret1098DC6E"},":SecretString:username::}}"]]}},{"Name":"POSTGRES_PASSWORD","Value":{"Fn::Join":["",["{{resolve:secretsmanager:",{"Ref":"DatabaseDbSecret1098DC6E"},":SecretString:password::}}"]]}},{"Name":"DATA_S3_BUCKET","Value":{"Ref":"StorageDataBucketB1B922FA"}},{"Name":"TRANSCRIPTION_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesTranscriptionQueueA02E7327","QueueName"]}},{"Name":"TRANSCRIPTION_DEADLETTER_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesTranscriptionDLQ6D36226D","QueueName"]}},{"Name":"LLM_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesLlmQueueE3526008","QueueName"]}},{"Name":"LLM_DEADLETTER_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesLlmDLQ37A16FA3","QueueName"]}},{"Name":"QUEUE_SERVICE_NAME","Value":"sqs"},{"Name":"STORAGE_SERVICE_NAME","Value":"s3"},{"Name":"AWS_DEFAULT_REGION","Value":{"Ref":"AWS::Region"}},{"Name":"AWS_REGION","Value":{"Ref":"AWS::Region"}},{"Name":"AWS_ACCOUNT_ID","Value":{"Ref":"AWS::AccountId"}},{"Name":"USE_LOCALSTACK","Value":"false"},{"Name":"REPO","Value":"minute"},{"Name":"FAST_LLM_PROVIDER","Value":"bedrock"},{"Name":"BEST_LLM_PROVIDER","Value":"bedrock"},{"Name":"FAST_LLM_MODEL_NAME","Value":"amazon.nova-lite-v1:0"},{"Name":"BEST_LLM_MODEL_NAME","Value":"anthropic.claude-sonnet-4-20250514-v1:0"},{"Name":"TRANSCRIPTION_SERVICES","Value":"[\"aws_transcribe\"]"},{"Name":"MAX_TRANSCRIPTION_PROCESSES","Value":"2"},{"Name":"MAX_LLM_PROCESSES","Value":"2"}],"Essential":true,"HealthCheck":{"Command":["CMD-SHELL","pgrep -f \"worker\" || exit 1"],"Interval":30,"Retries":5,"StartPeriod":300,"Timeout":10},"Image":{"Fn::Join":["",[{"Ref":"AWS::AccountId"},".dkr.ecr.",{"Ref":"AWS::Region"},".",{"Ref":"AWS::URLSuffix"},"/minute-worker:latest"]]},"LogConfiguration":{"LogDriver":"awslogs","Options":{"awslogs-group":{"Ref":"ComputeLogGroup1A40385B"},"awslogs-stream-prefix":"worker","awslogs-region":{"Ref":"AWS::Region"}}},"Name":"worker"}],"Cpu":"2048","ExecutionRoleArn":{"Fn::GetAtt":["ComputeExecutionRoleCE43D454","Arn"]},"Family":"MinuteStackComputeWorkerTaskDefB039BB33","Memory":"8192","NetworkMode":"awsvpc","RequiresCompatibilities":["FARGATE"],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"TaskRoleArn":{"Fn::GetAtt":["ComputeWorkerTaskRole3135DAE0","Arn"]}},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/WorkerTaskDef/Resource"}},"ComputeWorkerService489AD76D":{"Type":"AWS::ECS::Service","Properties":{"Cluster":{"Ref":"ComputeCluster4F8E5F81"},"DeploymentConfiguration":{"Alarms":{"AlarmNames":[],"Enable":false,"Rollback":false},"MaximumPercent":200,"MinimumHealthyPercent":50},"DesiredCount":1,"EnableECSManagedTags":false,"EnableExecuteCommand":true,"LaunchType":"FARGATE","NetworkConfiguration":{"AwsvpcConfiguration":{"AssignPublicIp":"ENABLED","SecurityGroups":[{"Fn::GetAtt":["NetworkingFargateSecurityGroupFC850E44","GroupId"]}],"Subnets":[{"Ref":"NetworkingVpcPublicSubnet1Subnet918289EE"},{"Ref":"NetworkingVpcPublicSubnet2Subnet9D9E5AFB"}]}},"ServiceName":"NdxMinute-Worker","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"TaskDefinition":{"Ref":"ComputeWorkerTaskDef5D93855B"}},"DependsOn":["ComputeWorkerTaskRoleDefaultPolicyA8BEE6C7","ComputeWorkerTaskRole3135DAE0"],"Metadata":{"aws:cdk:path":"MinuteStack/Compute/WorkerService/Service"}},"ComputeFrontendTaskDef9F702E49":{"Type":"AWS::ECS::TaskDefinition","Properties":{"ContainerDefinitions":[{"Environment":[{"Name":"ENVIRONMENT","Value":"local"},{"Name":"POSTGRES_HOST","Value":{"Fn::GetAtt":["DatabaseAuroraCF3B5693","Endpoint.Address"]}},{"Name":"POSTGRES_PORT","Value":{"Fn::GetAtt":["DatabaseAuroraCF3B5693","Endpoint.Port"]}},{"Name":"POSTGRES_DB","Value":"minute_db"},{"Name":"POSTGRES_USER","Value":{"Fn::Join":["",["{{resolve:secretsmanager:",{"Ref":"DatabaseDbSecret1098DC6E"},":SecretString:username::}}"]]}},{"Name":"POSTGRES_PASSWORD","Value":{"Fn::Join":["",["{{resolve:secretsmanager:",{"Ref":"DatabaseDbSecret1098DC6E"},":SecretString:password::}}"]]}},{"Name":"DATA_S3_BUCKET","Value":{"Ref":"StorageDataBucketB1B922FA"}},{"Name":"TRANSCRIPTION_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesTranscriptionQueueA02E7327","QueueName"]}},{"Name":"TRANSCRIPTION_DEADLETTER_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesTranscriptionDLQ6D36226D","QueueName"]}},{"Name":"LLM_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesLlmQueueE3526008","QueueName"]}},{"Name":"LLM_DEADLETTER_QUEUE_NAME","Value":{"Fn::GetAtt":["QueuesLlmDLQ37A16FA3","QueueName"]}},{"Name":"QUEUE_SERVICE_NAME","Value":"sqs"},{"Name":"STORAGE_SERVICE_NAME","Value":"s3"},{"Name":"AWS_DEFAULT_REGION","Value":{"Ref":"AWS::Region"}},{"Name":"AWS_REGION","Value":{"Ref":"AWS::Region"}},{"Name":"AWS_ACCOUNT_ID","Value":{"Ref":"AWS::AccountId"}},{"Name":"USE_LOCALSTACK","Value":"false"},{"Name":"PORT","Value":"8081"},{"Name":"NODE_ENV","Value":"production"},{"Name":"BACKEND_HOST","Value":"http://minute-backend.minute-internal:8080"}],"Essential":true,"HealthCheck":{"Command":["CMD-SHELL","wget -q --spider http://localhost:8081/health || exit 1"],"Interval":30,"Retries":5,"StartPeriod":300,"Timeout":10},"Image":{"Fn::Join":["",[{"Ref":"AWS::AccountId"},".dkr.ecr.",{"Ref":"AWS::Region"},".",{"Ref":"AWS::URLSuffix"},"/minute-frontend:latest"]]},"LogConfiguration":{"LogDriver":"awslogs","Options":{"awslogs-group":{"Ref":"ComputeLogGroup1A40385B"},"awslogs-stream-prefix":"frontend","awslogs-region":{"Ref":"AWS::Region"}}},"Name":"frontend","PortMappings":[{"ContainerPort":8081,"Protocol":"tcp"}]}],"Cpu":"512","ExecutionRoleArn":{"Fn::GetAtt":["ComputeExecutionRoleCE43D454","Arn"]},"Family":"MinuteStackComputeFrontendTaskDefE439C25A","Memory":"1024","NetworkMode":"awsvpc","RequiresCompatibilities":["FARGATE"],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"TaskRoleArn":{"Fn::GetAtt":["ComputeFrontendTaskRole8DA2A7B1","Arn"]}},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/FrontendTaskDef/Resource"}},"ComputeFrontendService389FAEFF":{"Type":"AWS::ECS::Service","Properties":{"Cluster":{"Ref":"ComputeCluster4F8E5F81"},"DeploymentConfiguration":{"Alarms":{"AlarmNames":[],"Enable":false,"Rollback":false},"MaximumPercent":200,"MinimumHealthyPercent":50},"DesiredCount":1,"EnableECSManagedTags":false,"EnableExecuteCommand":true,"HealthCheckGracePeriodSeconds":300,"LaunchType":"FARGATE","LoadBalancers":[{"ContainerName":"frontend","ContainerPort":8081,"TargetGroupArn":{"Ref":"ComputeALBHTTPFrontendTargetGroup18ED4AD1"}}],"NetworkConfiguration":{"AwsvpcConfiguration":{"AssignPublicIp":"ENABLED","SecurityGroups":[{"Fn::GetAtt":["NetworkingFargateSecurityGroupFC850E44","GroupId"]}],"Subnets":[{"Ref":"NetworkingVpcPublicSubnet1Subnet918289EE"},{"Ref":"NetworkingVpcPublicSubnet2Subnet9D9E5AFB"}]}},"ServiceName":"NdxMinute-Frontend","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"TaskDefinition":{"Ref":"ComputeFrontendTaskDef9F702E49"}},"DependsOn":["ComputeALBHTTPFrontendTargetRule851D3EBE","ComputeFrontendTaskRoleDefaultPolicy66A31476","ComputeFrontendTaskRole8DA2A7B1"],"Metadata":{"aws:cdk:path":"MinuteStack/Compute/FrontendService/Service"}},"ComputeALB00A47009":{"Type":"AWS::ElasticLoadBalancingV2::LoadBalancer","Properties":{"LoadBalancerAttributes":[{"Key":"deletion_protection.enabled","Value":"false"}],"Name":"NdxMinute-ALB","Scheme":"internet-facing","SecurityGroups":[{"Fn::GetAtt":["NetworkingAlbSecurityGroup5ADC578E","GroupId"]}],"Subnets":[{"Ref":"NetworkingVpcPublicSubnet1Subnet918289EE"},{"Ref":"NetworkingVpcPublicSubnet2Subnet9D9E5AFB"}],"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"Type":"application"},"DependsOn":["NetworkingVpcPublicSubnet1DefaultRoute80C01FA6","NetworkingVpcPublicSubnet1RouteTableAssociationD13830EA","NetworkingVpcPublicSubnet2DefaultRouteDF98F60F","NetworkingVpcPublicSubnet2RouteTableAssociation2D4CEA06"],"Metadata":{"aws:cdk:path":"MinuteStack/Compute/ALB/Resource"}},"ComputeALBHTTP30E88DD3":{"Type":"AWS::ElasticLoadBalancingV2::Listener","Properties":{"DefaultActions":[{"FixedResponseConfig":{"ContentType":"text/plain","MessageBody":"Service starting...","StatusCode":"503"},"Type":"fixed-response"}],"LoadBalancerArn":{"Ref":"ComputeALB00A47009"},"Port":80,"Protocol":"HTTP"},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/ALB/HTTP/Resource"}},"ComputeALBHTTPFrontendTargetGroup18ED4AD1":{"Type":"AWS::ElasticLoadBalancingV2::TargetGroup","Properties":{"HealthCheckIntervalSeconds":30,"HealthCheckPath":"/","HealthCheckTimeoutSeconds":10,"HealthyThresholdCount":2,"Matcher":{"HttpCode":"200-399"},"Port":8081,"Protocol":"HTTP","Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}],"TargetGroupAttributes":[{"Key":"deregistration_delay.timeout_seconds","Value":"30"},{"Key":"stickiness.enabled","Value":"false"}],"TargetType":"ip","UnhealthyThresholdCount":5,"VpcId":{"Ref":"NetworkingVpc6B5E6F44"}},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/ALB/HTTP/FrontendTargetGroup/Resource"}},"ComputeALBHTTPFrontendTargetRule851D3EBE":{"Type":"AWS::ElasticLoadBalancingV2::ListenerRule","Properties":{"Actions":[{"TargetGroupArn":{"Ref":"ComputeALBHTTPFrontendTargetGroup18ED4AD1"},"Type":"forward"}],"Conditions":[{"Field":"path-pattern","PathPatternConfig":{"Values":["/*"]}}],"ListenerArn":{"Ref":"ComputeALBHTTP30E88DD3"},"Priority":1},"Metadata":{"aws:cdk:path":"MinuteStack/Compute/ALB/HTTP/FrontendTargetRule/Resource"}},"CDNDistributionD4FAE585":{"Type":"AWS::CloudFront::Distribution","Properties":{"DistributionConfig":{"Comment":"Minute AI - HTTPS Termination","DefaultCacheBehavior":{"AllowedMethods":["GET","HEAD","OPTIONS","PUT","PATCH","POST","DELETE"],"CachePolicyId":"4135ea2d-6df8-44a3-9df3-4b5a84be39ad","Compress":true,"OriginRequestPolicyId":"216adef6-5c7f-47e4-b989-5492eafa07d3","TargetOriginId":"MinuteStackCDNDistributionOrigin1DF8764DE","ViewerProtocolPolicy":"redirect-to-https"},"Enabled":true,"HttpVersion":"http2","IPV6Enabled":true,"Origins":[{"CustomOriginConfig":{"OriginProtocolPolicy":"http-only","OriginSSLProtocols":["TLSv1.2"]},"DomainName":{"Fn::GetAtt":["ComputeALB00A47009","DNSName"]},"Id":"MinuteStackCDNDistributionOrigin1DF8764DE"}]},"Tags":[{"Key":"awsApplication","Value":{"Fn::GetAtt":["AppRegistryApplication","Arn"]}},{"Key":"Project","Value":"ndx-try-aws-scenarios"},{"Key":"Scenario","Value":"minute"}]},"Metadata":{"aws:cdk:path":"MinuteStack/CDN/Distribution/Resource"}}},"Outputs":{"MinuteUrl":{"Description":"URL to access Minute AI (HTTPS)","Value":{"Fn::Join":["",["https://",{"Fn::GetAtt":["CDNDistributionD4FAE585","DomainName"]}]]},"Export":{"Name":"MinuteStack-MinuteUrl"}},"CloudWatchLogsUrl":{"Description":"CloudWatch Logs URL","Value":{"Fn::Join":["",["https://",{"Ref":"AWS::Region"},".console.aws.amazon.com/cloudwatch/home?region=",{"Ref":"AWS::Region"},"#logsV2:log-groups/log-group/%2Fndx-minute"]]}},"DataBucketName":{"Description":"S3 bucket for audio data","Value":{"Ref":"StorageDataBucketB1B922FA"}}},"Conditions":{"CDKMetadataAvailable":{"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"af-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-3"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-4"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-2"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"il-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]}]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}}} \ No newline at end of file diff --git a/cloudformation/scenarios/paperless-ngx/cdk/lib/constructs/compute.ts b/cloudformation/scenarios/paperless-ngx/cdk/lib/constructs/compute.ts index b454d68b..05af0c22 100644 --- a/cloudformation/scenarios/paperless-ngx/cdk/lib/constructs/compute.ts +++ b/cloudformation/scenarios/paperless-ngx/cdk/lib/constructs/compute.ts @@ -162,7 +162,7 @@ export class ComputeConstruct extends Construct { ); const tikaContainer = this.taskDefinition.addContainer('tika', { - image: ecs.ContainerImage.fromRegistry('docker.io/apache/tika:latest'), + image: ecs.ContainerImage.fromRegistry('docker.io/apache/tika:3.3.0.0-full@sha256:ecdd37e204308266b1f8e28569f8516ebd5b96d7a4518a71d3904710b20c03b3'), essential: true, logging: ecs.LogDrivers.awsLogs({ logGroup: this.logGroup, streamPrefix: 'tika' }), portMappings: [{ containerPort: 9998, protocol: ecs.Protocol.TCP }], @@ -188,7 +188,7 @@ export class ComputeConstruct extends Construct { const dbPass = props.databaseSecret.secretValueFromJson('password').unsafeUnwrap(); const paperlessContainer = this.taskDefinition.addContainer('paperless', { - image: ecs.ContainerImage.fromRegistry('ghcr.io/paperless-ngx/paperless-ngx:latest'), + image: ecs.ContainerImage.fromRegistry('ghcr.io/paperless-ngx/paperless-ngx:2.9@sha256:948dc7297df8259bffac23e564a7ca688bfc8f04fed9113e7fb14f6030da63dd'), essential: true, logging: ecs.LogDrivers.awsLogs({ logGroup: this.logGroup, streamPrefix: 'paperless' }), portMappings: [{ containerPort: 8000, protocol: ecs.Protocol.TCP }], diff --git a/cloudformation/scenarios/planx/cdk/lib/constructs/compute.ts b/cloudformation/scenarios/planx/cdk/lib/constructs/compute.ts index e62482e8..f5a5308c 100644 --- a/cloudformation/scenarios/planx/cdk/lib/constructs/compute.ts +++ b/cloudformation/scenarios/planx/cdk/lib/constructs/compute.ts @@ -134,7 +134,7 @@ export class ComputeConstruct extends Construct { // 3. Pre-creates extensions (postgis, pgcrypto, fuzzystrmatch, pg_cron, etc.) // 4. Then runs the standard Hasura cli-migrations entrypoint hasuraTaskDef.addContainer('hasura-engine', { - image: ecs.ContainerImage.fromRegistry(`${ghcrPrefix}-hasura:latest`), + image: ecs.ContainerImage.fromRegistry('ghcr.io/co-cddo/ndx_try_aws_scenarios-planx-hasura:sha-e748ef5@sha256:0d81caa04dccbbc890a589e709eb0d98c727b64768f34c95185137a05d768c8b'), logging: ecs.LogDrivers.awsLogs({ logGroup, streamPrefix: 'hasura' }), environment: { HASURA_GRAPHQL_DATABASE_URL: databaseUrl, @@ -209,7 +209,7 @@ export class ComputeConstruct extends Construct { ].join(' && '); apiTaskDef.addContainer('api', { - image: ecs.ContainerImage.fromRegistry(`${ghcrPrefix}-api:latest`), + image: ecs.ContainerImage.fromRegistry('ghcr.io/co-cddo/ndx_try_aws_scenarios-planx-api:sha-e748ef5@sha256:9f765c0130675218066d11178b2dc7275cd8c1f8916af5583c25ddbb9e03bd79'), logging: ecs.LogDrivers.awsLogs({ logGroup, streamPrefix: 'api' }), environment: { ...sharedEnv, @@ -301,7 +301,7 @@ export class ComputeConstruct extends Construct { }); sharedbTaskDef.addContainer('sharedb', { - image: ecs.ContainerImage.fromRegistry(`${ghcrPrefix}-sharedb:latest`), + image: ecs.ContainerImage.fromRegistry('ghcr.io/co-cddo/ndx_try_aws_scenarios-planx-sharedb:sha-e748ef5@sha256:e998deeb6246e92568a2993e4e3dd5579edad77ef26bcc9e7c131606211b4c03'), logging: ecs.LogDrivers.awsLogs({ logGroup, streamPrefix: 'sharedb' }), environment: { ...sharedEnv, @@ -350,7 +350,7 @@ export class ComputeConstruct extends Construct { }); editorTaskDef.addContainer('editor', { - image: ecs.ContainerImage.fromRegistry(`${ghcrPrefix}-editor:latest`), + image: ecs.ContainerImage.fromRegistry('ghcr.io/co-cddo/ndx_try_aws_scenarios-planx-editor:sha-e748ef5@sha256:99212cef72aa68c8119e387409e3ae8f37087a36d47128487c8e1b02cd5d8d8b'), logging: ecs.LogDrivers.awsLogs({ logGroup, streamPrefix: 'editor' }), environment: { // Editor SPA uses relative paths for API/Hasura and window.location.host for WebSockets diff --git a/renovate.json b/renovate.json new file mode 100644 index 00000000..3687e08d --- /dev/null +++ b/renovate.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + ":dependencyDashboard", + ":semanticCommits" + ], + "timezone": "Europe/London", + "platform": "github", + "labels": ["renovate"], + "osvVulnerabilityAlerts": true, + "vulnerabilityAlerts": { + "labels": ["security", "security-priority"], + "groupName": "security-priority", + "schedule": ["at any time"], + "minimumReleaseAge": null + }, + "rangeStrategy": "bump", + "configMigration": true, + "ignorePaths": [ + "**/node_modules/**", + "**/cdk.out/**", + "**/.aws-sam/**", + "**/dist/**", + "**/.upstream/**" + ], + "customManagers": [ + { + "customType": "regex", + "description": "Pin GHCR + docker.io image references in CDK TypeScript and raw CFN templates. Renovate's built-in docker manager does not cover ecs.ContainerImage.fromRegistry() string literals; this manager does.", + "fileMatch": [ + "^cloudformation/scenarios/.*\\.(ts|yaml|yml|json)$" + ], + "matchStrings": [ + "(?(?:ghcr\\.io|docker\\.io)/[a-z0-9._/-]+):(?[a-z0-9.\\-]+)@(?sha256:[a-f0-9]+)" + ], + "datasourceTemplate": "docker", + "versioningTemplate": "docker" + } + ], + "packageRules": [ + { + "description": "Pin discipline: NEVER replace a digest with a bare tag; updates must carry both.", + "matchCustomManagers": ["custom.regex"], + "pinDigests": true + }, + { + "description": "Own GHCR images — one PR per scenario; immediate when an image bumps. Smoke runs scoped to that scenario give fast feedback.", + "groupName": "scenario-{{packageName}}", + "matchCustomManagers": ["custom.regex"], + "matchPackagePatterns": [ + "^ghcr\\.io/co-cddo/ndx_try_aws_scenarios-" + ], + "schedule": ["at any time"] + }, + { + "description": "Upstream container deps (tika, paperless-ngx, gotenberg). Weekly grouped per image to keep blast radius small.", + "groupName": "upstream-{{packageName}}", + "matchCustomManagers": ["custom.regex"], + "matchPackagePatterns": [ + "^docker\\.io/apache/tika", + "^docker\\.io/gotenberg/gotenberg", + "^ghcr\\.io/paperless-ngx/paperless-ngx" + ], + "schedule": ["before 09:00 on monday"] + }, + { + "description": "npm dev deps — weekly batched. Low-risk; noise control.", + "matchManagers": ["npm"], + "matchDepTypes": ["devDependencies"], + "groupName": "npm-dev", + "schedule": ["before 09:00 on monday"] + }, + { + "description": "npm prod deps — weekly batched. Higher risk; smoke gates the merge.", + "matchManagers": ["npm"], + "matchDepTypes": ["dependencies"], + "groupName": "npm-prod", + "schedule": ["before 09:00 on monday"] + }, + { + "description": "Drupal composer deps. Same cadence as npm-prod.", + "matchManagers": ["composer"], + "groupName": "composer", + "schedule": ["before 09:00 on monday"] + }, + { + "description": "GitHub Actions — workflow action references. Weekly batched; action bumps rarely break. pinDigests scoped to OUR workflows; third-party actions in docker-build scripts (renovatebot/github-action etc.) keep their explicit digest pins because the workflow author already chose them.", + "matchManagers": ["github-actions"], + "matchFileNames": [".github/workflows/*"], + "groupName": "github-actions", + "schedule": ["before 09:00 on monday"] + }, + { + "description": "Pin official actions/* and aws-actions/* references in workflows to digest. Other action sources (community / vendor-specific) keep their existing pin shape — pinning everything caused a firehose in past adoption.", + "matchManagers": ["github-actions"], + "matchPackagePatterns": [ + "^actions/", + "^aws-actions/" + ], + "pinDigests": true + }, + { + "description": "Python pip Lambda layer deps — batched weekly with npm-dev cadence.", + "matchManagers": ["pip_requirements", "pip-compile"], + "groupName": "pip", + "schedule": ["before 09:00 on monday"] + } + ], + "prConcurrentLimit": 6, + "prHourlyLimit": 4, + "branchConcurrentLimit": 12 +}