├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── THIRD_PARTY_NOTICES ├── architecture.drawio ├── architecture.png ├── bin └── cicd.ts ├── cdk.json ├── config └── config.ts ├── cross-account └── deployment-role.yaml ├── docs ├── admin.md ├── developer.md ├── images │ └── new_secret_01.png └── prereq.md ├── lambda-helpers ├── email-handler │ └── lambda.py ├── layers │ └── python3_layer.zip └── semver-handler │ └── lambda.py ├── lib ├── cicd-s3-stack.ts ├── cicd-stack.ts ├── emailHandler-stack.ts ├── iam │ ├── code-build-role.ts │ └── pipeline-role.ts ├── pipelines │ └── simple-cicd-pipeline.ts ├── projects │ ├── build-project-environment.ts │ ├── build-project.ts │ ├── deploy-project-environment.ts │ ├── deploy-project.ts │ └── test-project.ts └── semverHandler-stack.ts ├── package-lock.json ├── package.json ├── project-config.sample.json ├── scripts ├── assume-cross-account-role.env ├── build.sh ├── deploy.sh └── test.sh ├── simple-cicd.code-workspace └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules 3 | .idea 4 | *~ 5 | .build 6 | .pt 7 | *.swp 8 | .DS_Store 9 | .nyc_output/ 10 | *.csv 11 | *.tgz 12 | # Logs 13 | logs 14 | *.log 15 | npm-debug.log 16 | .tmp 17 | 18 | # Runtime data 19 | pids 20 | *.pid 21 | *.seed 22 | dist 23 | 24 | # Directory for instrumented libs generated by jscoverage/JSCover 25 | lib-cov 26 | 27 | # Coverage directory used by tools like istanbul 28 | coverage 29 | 30 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (http://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | **/.idea 40 | .serverless/ 41 | *.sw? 42 | vim-markdown-preview.html 43 | .vscode/ 44 | # Temporary output generate during build 45 | build-artifacts/ 46 | 47 | # Temporary Git repo for checking changes 48 | _GIT_REPO/ 49 | .vscode/ 50 | 51 | *.gitignored 52 | 53 | # Compiled class file 54 | *.class 55 | 56 | # Maven 57 | **/target/ 58 | **/.settings/ 59 | 60 | # CDK 61 | **/cdk.out/ 62 | *.js 63 | *.d.ts 64 | 65 | # Simple-CICD specific files 66 | project-config.json 67 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 4 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 5 | opensource-codeofconduct@amazon.com with any additional questions or comments. 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | ## Reporting Bugs/Feature Requests 10 | 11 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 12 | 13 | When filing an issue, please check [existing open](https://github.com/awslabs/aws-simple-cicd/issues), or [recently closed](https://github.com/awslabs/aws-simple-cicd/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 14 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 15 | 16 | * A reproducible test case or series of steps 17 | * The version of our code being used 18 | * Any modifications you've made relevant to the bug 19 | * Anything unusual about your environment or deployment 20 | 21 | ## Contributing via Pull Requests 22 | 23 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 24 | 25 | 1. You are working against the latest source on the *master* branch. 26 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 27 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 28 | 29 | To send us a pull request, please: 30 | 31 | 1. Fork the repository. 32 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 33 | 3. Ensure local tests pass. 34 | 4. Commit to your fork using clear commit messages. 35 | 5. Send us a pull request, answering any default questions in the pull request interface. 36 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 37 | 38 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 39 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 40 | 41 | ## Finding contributions to work on 42 | 43 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-simple-cicd/labels/help%20wanted) issues is a great place to start. 44 | 45 | ## Code of Conduct 46 | 47 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 48 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 49 | opensource-codeofconduct@amazon.com with any additional questions or comments. 50 | 51 | ## Security issue notifications 52 | 53 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 54 | 55 | ## Licensing 56 | 57 | See the [LICENSE](https://github.com/awslabs/aws-simple-cicd/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 58 | 59 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | SPDX-License-Identifier: MIT-0 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 7 | software and associated documentation files (the "Software"), to deal in the Software 8 | without restriction, including without limitation the rights to use, copy, modify, 9 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 14 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 15 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 16 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 17 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOTICE 2 | [CodePipeline now natively supports Branches, PRs and Monorepos.](https://aws.amazon.com/blogs/devops/aws-codepipeline-adds-support-for-branch-based-development-and-monorepos/) This repository will no longer be maintained and we recommend you leverage the native functionality! 3 | 4 | --- 5 | 6 | # AWS-Simple-CICD Project 7 | 8 | This project provides a serverless CI/CD platform leveraging native AWS services provisioned using the AWS Cloud Development Kit (CDK). As per the AWS Well Architected Framework, this project assumes the use of multiple AWS accounts for secure isolation of environments. 9 | 10 | This CI/CD platform is in use at a variety of AWS clients where the development teams are leveraging CloudFormation, Serverless Framework, AWS CDK and Terraform. 11 | 12 | ## Getting started 13 | 14 | - [Pre-Requisites](docs/prereq.md) 15 | - [Administrator Guide](docs/admin.md) 16 | - [Developer Guide](docs/developer.md) 17 | 18 | ## Goals 19 | 20 | - Pipelines as code. 21 | - Bring Developers closer to their infrastructure and operations by providing a prescriptive platform. 22 | - Support for (almost) any toolset the application developers want to use e.g. Terraform, CDK, Cloudformation, Pulumi etc. 23 | - Minimize platform lock-in. Applications can be migrated to other CI/CD orchestration platform with minimal changes required by the developers. 24 | - Enables "you build it, you run it". 25 | 26 | ## Features 27 | 28 | - Cloud native and built on top of [AWS Serverless CI/CD tools](https://aws.amazon.com/serverless/developer-tools/) 29 | - Runs on top of [AWS Landing Zone](https://aws.amazon.com/solutions/implementations/aws-landing-zone/)/[Control Tower](https://aws.amazon.com/controltower/) 30 | - Supports pipeline notifications via [AWS SNS](https://aws.amazon.com/sns/) 31 | - Supports branches (pipeline per branch) 32 | - Auto-increments [semantic versioning](https://www.semver.org) per pipeline. 33 | 34 | ## Architecture 35 | 36 | This is the pipeline that will be generated for each repository. The build and deployment stages in the pipeline execute a user defined shell script in an isolated docker container. The docker environment is provisioned on the fly by AWS CodeBuild. 37 | 38 | The number of stages and their function is fully customizable e.g. adding a stage for security/vulnerability scanning, adding a stage for executing test cases etc. 39 | 40 | ![Architecture](./architecture.png "CI/CD Architecture") 41 | 42 | ### AWS services 43 | 44 | - AWS CodeCommit (or any source control providor supported by CodePipeline) 45 | - AWS CodePipeline 46 | - AWS CodeBuild 47 | - AWS Lambda 48 | - AWS S3 49 | - AWS SNS 50 | - AWS CloudWatch 51 | - AWS Systems Manager: Parameter Store 52 | - AWS CloudFormation 53 | -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES: -------------------------------------------------------------------------------- 1 | ** python-semver; version 2.9.1 -- 2 | https://github.com/python-semver/python-semver 3 | Copyright (c) 2013, Konstantine Rybnikov 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | Redistributions in binary form must reproduce the above copyright notice, 14 | this 15 | list of conditions and the following disclaimer in the documentation and/or 16 | other materials provided with the distribution. 17 | 18 | Neither the name of the {organization} nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | FOR 27 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 30 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /architecture.drawio: -------------------------------------------------------------------------------- 1 | 7VvZbuM2FP0aA+1DA62W/eglyRRIgQAuMJOngJZoma0kqhTlpV/fS4m0FsrNBF6UzDgTILqXFJfDc0heUjOwZ/HukaF0/QcNcDSwjGA3sOcDyzLH1hD+CM++9Ixto3SEjAQyU+VYkH+xdKpsOQlw1sjIKY04SZtOnyYJ9nnDhxij22a2FY2ataYoxJpj4aNI934lAV+X3pFrVP4vmIRrVbNpyJQYqczSka1RQLc1l30/sGeMUl4+xbsZjgR4CpfyvYcjqYeGMZzw73nBKl/YoCiXfZt8XYBjFtE8kE3ke9XvlJKEF9i5U/iFomfGwIWUmbDuLLflaNte02Hqliij6WjbXtNhtos3W/Wb7QbWHJrVKN5o1W/UGgi/9pTmPCIJnh1YZoAzZCgggP6MRpSBL6EJoDdd8zgCy4TH7ZpwvEiRL1DdgkLAt6IJlzw3LWVL4EWpwJNUPMe7UEjqDm0z5y5kNE+LKn8HpnemvsLjqy8G8xVFXBTEGf0bq8YNLBv+PQhuTFckilqN3mDGCdB+EpFQlM+pqA5JK8KrokToCUnCp8Ka24ZsfVcVAcrWOJBd0qkq2StqxbuaS1L3EdMYc7aHLDJ1JFUkpxFHmttKk54S2rqmx6F6D8l5IDyUXEkFHqRaupUz1JSzWENfggVmG+LD7GQZE9+nOXTuJqMfR0Y/moRMs6mhg10Tke10iMh1XUGMU2VkazKa481NOzftfALtDJ2WdlxdO6bdoZ2D8xTlOJpy/sQZv0nnJp1PKB3bsgoCXE09rqaeZ0aDm3pu6vmE6nFG11x4TFsTBw5CrIaMMr6mIU1QdF95pzAgSXDAoMrzRAW2BTf+wpzvJRFQzmmTOUdhy2jOfNwIyjhiIeaNDaZo4f9Cy3CEONk0T3hOgsnpAyZAh+2/yfcL40UYIGVpznf1xPn+LVa+Aa/TG7xuL/DuCP9We66BC1aFrTBOhdbtC1pPWxtnNIC5M46Jvi52LgTHJsL2AgFpztyDxFranDAoiBSTeiKGqDVHwzvw40zHXbP6qvhpT7lqPn9CSxw904zI4peUcxq/OeH70CrMmkR4a9FCWVrCsSI7HBxbxRguOVCuYVMwu1YzH9D3S/TPsnzYbituGVna8uGN9NVD+U7h1ljj1hOKlwEC3xccpZhlZ2fYgze6N5z3MWxuuDPT+2kYFpVjcBF2Oeb12GWaGr00OlVrwLEN6ffsOt5xwjZs4mF1nLCZXcfUjnOGzdqocy5/JikWmrrN5v3M5qnC/zwMG5nN+bzjHOpiitNvEAXBpjmJghu7+mHXsgD/IpO5bZjXo1bHFRtEc8YvCAZghQAxa1jcaS4ZPIXl7SZlKMS/np15Q2Ni2977mGd5ngl9+FmYl9mXoZzbda17IcpZ/QSVh5i9CtNfBvUo/YSY3ZTRXD2yVLuNHqJ2PbZ8xLxq8vHNmnGdzVrrkwJrqJNv1LVXOwM26gzgA56rKcI0SGT2RSLVmhqJuvcbfbPHtq7IHu/jskd9o1dnj9Ube/QYcY7TiIrKoHuWUXyA8NGY1HHCfzEmjXpZBOXJanWa+lJL6T5ZvejCqRjaYG1vx92qNUdZW17+fzDaOs74erTt+pSojlB5wds3Qmqbqna34ysKe3wTdk3EDWH3dk3Y8R2PimtFtNYYruE/OVUJv2UF4BPIME53VZoKhSdpyigUqgfJygMtK2tQ7rY01jRe5tl1ZDG2m7Iwxnf65yBuhzDc948BmNUX9kVa7f8p2Pf/AQ== -------------------------------------------------------------------------------- /architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awslabs/aws-simple-cicd/1ff4a03eda6416ace2d4a945d3cd6de68f5d396d/architecture.png -------------------------------------------------------------------------------- /bin/cicd.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import 'source-map-support/register' 21 | import * as cdk from 'aws-cdk-lib' 22 | import { CicdStack } from '../lib/cicd-stack' 23 | import { S3Stack } from '../lib/cicd-s3-stack' 24 | import { EmailHandlerStack } from '../lib/emailHandler-stack' 25 | import { SemverHandlerStack } from '../lib/semverHandler-stack' 26 | import {default as config } from '../config/config' 27 | 28 | // Setup prefix 29 | let prefix = `${config.naming.company}-${config.naming.dept}-${config.naming.project}` 30 | let ssmRoot = `/${config.naming.company}/${config.naming.dept}/${config.naming.project}` 31 | let cicdRoleName = config.deployment['cicdRoleName'] 32 | 33 | const app = new cdk.App() 34 | 35 | new S3Stack(app, 'AWS-Simple-CICD-01-S3', { prefix, ssmRoot }) 36 | new EmailHandlerStack(app, 'AWS-Simple-CICD-02-EmailHandler', { prefix, ssmRoot }) 37 | new SemverHandlerStack(app, 'AWS-Simple-CICD-03-SemverHandler', { prefix, ssmRoot }) 38 | new CicdStack(app, 'AWS-Simple-CICD-04-SeedPipeline', { prefix, ssmRoot, cicdRoleName, repos: config.seedPipeline}) 39 | new CicdStack(app, 'AWS-Simple-CICD-TeamOne', { prefix, ssmRoot, cicdRoleName, repos: config.teamOne}) 40 | //new CicdStack(app, 'TeamTWo-CICD', { prefix, ssmRoot, repos: config.teamTwo}) -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "node bin/cicd.js" 3 | } 4 | -------------------------------------------------------------------------------- /config/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import configFile from "../project-config.json" 21 | 22 | export enum TriggerType { 23 | CodeCommit = "CodeCommit", 24 | GitHub = "GitHub" 25 | } 26 | 27 | export enum Regions { 28 | CanadaCentral="CA-CENTRAL-1" 29 | } 30 | 31 | export enum StageName { 32 | cicd = 'cicd', 33 | dev = 'dev', 34 | test = 'test', 35 | prod = 'prod' 36 | } 37 | 38 | export type ProjectRepo = { 39 | pipelineName: string, 40 | repository: string, 41 | branch: string, 42 | type: TriggerType, 43 | owner?: any, 44 | secret?: any, 45 | cron?: any, 46 | targets?: any 47 | } 48 | 49 | export interface ProjectConfig { 50 | naming: { 51 | company: string, 52 | dept: string, 53 | project: string 54 | }, 55 | deployment: { 56 | region: string, 57 | cicdRoleName: string 58 | githubSecret: string 59 | }, 60 | accountIds: { 61 | cicd: string, 62 | dev: string, 63 | test: string, 64 | prod: string 65 | }, 66 | sharedResources: { 67 | cicdBucket: string 68 | }, 69 | defaultRegions: { 70 | cicd: string, 71 | dev: string, 72 | test: string, 73 | prod: string 74 | }, 75 | seedPipeline: Array, 76 | teamOne: Array 77 | } 78 | 79 | const config = configFile 80 | 81 | export default config -------------------------------------------------------------------------------- /cross-account/deployment-role.yaml: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # SPDX-License-Identifier: MIT-0 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | # software and associated documentation files (the "Software"), to deal in the Software 7 | # without restriction, including without limitation the rights to use, copy, modify, 8 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | ### 18 | 19 | Parameters: 20 | SharedAccountId: 21 | Type: String 22 | Description: Enter the account id of the shared account 23 | 24 | Resources: 25 | DeploymentRole: 26 | Type: AWS::IAM::Role 27 | Properties: 28 | RoleName: deployment-role 29 | AssumeRolePolicyDocument: 30 | Version: 2012-10-17 31 | Statement: 32 | - Effect: Allow 33 | Principal: 34 | AWS: 35 | - !Ref SharedAccountId 36 | Action: 37 | - 'sts:AssumeRole' 38 | 39 | DeploymentPolicy: 40 | Type: AWS::IAM::Policy 41 | Properties: 42 | PolicyName: deployment-policy 43 | PolicyDocument: 44 | Version: 2012-10-17 45 | Statement: 46 | - Effect: Allow 47 | Action: 48 | - 'codepipeline:*' 49 | - 'codebuild:*' 50 | - 'iam:*' 51 | - 'sns:*' 52 | - 'cloudformation:*' 53 | - 'lambda:*' 54 | - 'ec2:*' 55 | - 'eks:*' 56 | - 'ecs:*' 57 | - 'ecr:*' 58 | - 'events:*' 59 | - 'cloudwatch:*' 60 | - 'ssm:*' 61 | - 's3:*' 62 | - 'states:*' 63 | - 'serverlessrepo:*' 64 | - 'apigateway:*' 65 | - 'secretsmanager:*' 66 | - 'logs:*' 67 | Resource: '*' 68 | Roles: 69 | - !Ref DeploymentRole 70 | 71 | DeploymentRoleNameParameter: 72 | Type: AWS::SSM::Parameter 73 | Properties: 74 | Name: /cicd/deployment-role-name 75 | Type: String 76 | Value: deployment-role 77 | Description: Cross-Account CICD role name 78 | 79 | DeploymentRoleArnParameter: 80 | Type: AWS::SSM::Parameter 81 | Properties: 82 | Name: /cicd/deployment-role-arn 83 | Type: String 84 | Value: !GetAtt DeploymentRole.Arn 85 | Description: Cross-Account CICD role arn 86 | 87 | -------------------------------------------------------------------------------- /docs/admin.md: -------------------------------------------------------------------------------- 1 | # Administrator Guide 2 | 3 | These instructions are for the users who will be deploying and maintaining the platform. 4 | 5 | 0. [Setup project config](#setup-project-config) 6 | 1. [Configure accounts](#configure-accounts) 7 | 2. [Configure naming](#configure-naming) 8 | 3. [Configure pipelines](#configure-pipelines) 9 | 4. [Grouping pipelines](#grouping-pipelines) 10 | 5. [Overriding target environments](#overriding-target-environments) 11 | 6. [Deploying pipelines](#deploying-pipelines) 12 | 13 | ## Setup Project Config 14 | 15 | Create a [project-config.json](../project-config.sample.json) file in the root of the Simple-CICD project. There is a sample ***project-config.sample.json*** file provided 16 | 17 | ## Configure Accounts 18 | 19 | Add the account ids of the target accounts to the project-config.json file. The account Id will be passed to the deployment stage as an environment variable. Leave the account id blank (but do not remove the key e.g. dev, test, prod) for any environment you do not want to target. 20 | 21 | ```text 22 | { 23 | dev: string, 24 | test: string, 25 | prod: string 26 | } 27 | ``` 28 | 29 | Example: 30 | 31 | ```json 32 | { 33 | "dev": "123456789000", 34 | "test": "123456789001", 35 | "prod": "123456789002" 36 | } 37 | ``` 38 | 39 | ### Deploy cross-account IAM role *(if needed)* 40 | 41 | If you already have a cross-account role set up for deployments, then skip step 1. 42 | 43 | #### Step 1 44 | 45 | The pipelines will be deployed and executed in the Shared Services account. The pipeline will need to assume an IAM role in the target accounts in order to provision resources. 46 | 47 | A sample IAM role and profile is provided in this project if this does not already exist. Modify [deployment-role.yaml](../cross-account/deployment-role.yaml) based on your requirements and deploy it using the following commands. This role will need to be deployed to each target (dev, test and prod) AWS account. 48 | 49 | ```bash 50 | cd cross-account 51 | 52 | aws cloudformation deploy --template-file deployment-role.yaml --stack-name cicd-iam-stack --capabilities CAPABILITY_NAMED_IAM --parameter-overrides SharedAccountId={SHARED-ACCOUNT-ID} 53 | ``` 54 | Note: Replace {SHARED-ACCOUNT-ID} with the appropiate ID. 55 | 56 | The IAM role name in the sample provided is ***deployment-role***. 57 | 58 | #### Step 2 59 | 60 | Set the cross-account role name in the [sample](../project-config.sample.json) file. Update ***cicdRoleName***. If you are using Github, set ***githubSecret*** to an AWS Secrets Manager secret storing the Github personal access token. (optional) 61 | 62 | ```bash 63 | "deployment": { 64 | "region": "ca-central-1", 65 | "cicdRoleName": "deployment-role", 66 | "githubSecret": "github-token" 67 | }, 68 | ``` 69 | 70 | ## Configure Naming 71 | 72 | All the AWS resources provisioned by this project will follow a standard naming convention. This can be configured as desired. 73 | 74 | ```text 75 | { 76 | company: string, 77 | dept: string, 78 | project: string 79 | } 80 | ``` 81 | 82 | Example: 83 | 84 | This will generate resources prefixed with ***acme-markets-roadrunner*** 85 | 86 | ```json 87 | { 88 | "company": "acme", 89 | "dept": "markets", 90 | "project": "roadrunner" 91 | } 92 | ``` 93 | 94 | ## Configure Pipelines 95 | 96 | - The pipeline name and branch are concatenated to create a unique pipeline per branch. 97 | - The sample provides a single TriggerType - CodeCommit. This can be extended to add Github, BitBucket etc. 98 | - An SNS Topic is generated for the pipeline. Subscribers receive notifications on status of each pipeline stage. Emails are sent by a Lambda function. 99 | - A Parameter Store parameter is generated which stores the semantic version and automatically increments (uses python semver library) on every successful build. 100 | - A Cron parameter can be set to trigger the pipeline on a schedule managed by CloudWatch. (optional) 101 | 102 | ```text 103 | { 104 | pipelineName: string, 105 | ccRepoName: string, 106 | branch: string, 107 | type: TriggerType, 108 | cron: string, 109 | } 110 | ``` 111 | 112 | ### GitHub Example 113 | 114 | **Note** GitHub integration uses personal access tokens. See: [https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) 115 | 116 | In AWS Secrets Manager create a plain text secret where the value is your Github personal access token. In this example the secret is called ***github-token*** 117 | 118 | ![New Secret](images/new_secret_01.png "New Secret") 119 | 120 | 121 | This sample will generate a pipeline called ***acme-markets-roadrunner-infra-eks-main*** 122 | 123 | ```json 124 | { 125 | "pipelineName": "infra-eks", 126 | "repository": "acme-infra-eks", 127 | "branch": "main", 128 | "type": "GitHub", 129 | "owner": "owner", 130 | } 131 | ``` 132 | 133 | ### CodeCommit Example 134 | 135 | This sample will generate a pipeline called ***acme-markets-roadrunner-rocket-powered-skates-master*** 136 | 137 | ```json 138 | { 139 | "pipelineName": "rocket-powered-skates", 140 | "ccRepoName": "rocket-powered-skates", 141 | "branch": "master", 142 | "type": "CodeCommit", 143 | } 144 | ``` 145 | 146 | ## Grouping Pipelines 147 | 148 | AWS CloudFormation has a limit of 500 resources per stack. To bypass this limitation we recommend grouping pipelines together and generating a separate stack for each group. In the [sample](../project-config.sample.json) the pipelines are grouped by team, Team One and Team Two. 149 | 150 | ### Adding a new group 151 | 152 | 1. Create a new array in project-config.json for Team Three. See teamOne or teamTwo for an example. 153 | 154 | ```bash 155 | "teamThree": [ 156 | { 157 | "pipelineName": "rocket-powered-skates", 158 | "ccRepoName": "rocket-powered-skates", 159 | "branch": "master", 160 | "type": "CodeCommit", 161 | "cron": "" 162 | } 163 | ] 164 | ``` 165 | 166 | 1. Update [config.ts](../config/config.ts) and update the ProjectConfig interface by exporting the configuration for Team Three. 167 | 168 | ```bash 169 | teamThree: Array 170 | ``` 171 | 172 | 1. Update [cicd.ts](../bin/cicd.ts) to generate a new stack for Team Three. 173 | 174 | ```bash 175 | new CicdStack(app, 'AWS-Simple-CICD-TeamThree', { prefix, ssmRoot, repos: config.teamThree}) 176 | ``` 177 | 178 | Group your pipelines based on your needs. Grouping by teams is just provided as an example. 179 | 180 | ## Overriding target environments 181 | 182 | In some situations you may want to pick and choose which target environments the pipeline should deploy to. For example when you want to build a feature branch you do not want it to deployed to production. In this situation you can set the targets array to override the default behavior where every pipeline pushes all the way to production. 183 | 184 | ```json 185 | { 186 | "pipelineName": "rocket-powered-skates", 187 | "ccRepoName": "rocket-powered-skates", 188 | "branch": "feature/ticket-1234", 189 | "type": "Github", 190 | "owner": "Owner", 191 | "targets": ["dev", "test"] 192 | } 193 | ``` 194 | 195 | ## Deploying Pipelines 196 | 197 | If you have not installed AWS CDK already please refer to the [pre-requisites](./prereq.md) 198 | 199 | ```bash 200 | npm install 201 | 202 | npm run build 203 | 204 | # The bootstrap only needs to be executed once 205 | cdk bootstrap --profile 206 | 207 | cdk deploy --all --profile 208 | ``` 209 | -------------------------------------------------------------------------------- /docs/developer.md: -------------------------------------------------------------------------------- 1 | # Developer Guide 2 | 3 | These instructions are for the application developers who will be using the CI/CD platform to deliver their applications. 4 | 5 | As the developer you are responsible for maintaining a scripts folder with three files in the root of your code repository. 6 | 7 | ```text 8 | scripts/build.sh 9 | 10 | scripts/test.sh 11 | 12 | scripts/deploy.sh 13 | ``` 14 | 15 | The build,test and deploy scripts must contain all the commands required to build your application, including the installation of any dependencies. The pipeline will execute the build and test scripts once per run. The deploy script will be executed once per target environment i.e dev, test and prod. 16 | 17 | This enforces the *"build once, deploy many"* paradigm and also ensures that your deployment script is environment agnostic. 18 | 19 | Finally, you as the developer are now in complete control of how your applications get deployed to your AWS accounts. 20 | 21 | ## Detailed Instructions 22 | 23 | Create a directory called scripts in the root of the application source code repository called ***scripts*** with 3 files: 24 | 25 | 1. build.sh 26 | 27 | Sample bash script which will build a Java application, generate a Docker image and push it to ECR 28 | 29 | ```bash 30 | #! /bin/bash 31 | 32 | set -e 33 | set -u 34 | set -o pipefail 35 | 36 | # Build Java App 37 | mvn clean deploy --no-transfer-progress 38 | 39 | # Push container to ECR in shared services 40 | REPOSITORY_URI="0000000000.dkr.ecr.eu-central-1.amazonaws.com/acme/roadrunner/rocket-powered-skates" 41 | COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) 42 | IMAGE_TAG=${COMMIT_HASH:=latest} 43 | 44 | $(aws ecr get-login --region ca-central-1 --no-include-email) 45 | docker build -t $REPOSITORY_URI:latest . 46 | docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG 47 | docker push $REPOSITORY_URI:latest 48 | docker push $REPOSITORY_URI:$IMAGE_TAG 49 | ``` 50 | 51 | Sample build script for a project which doesn't require a build 52 | 53 | ```bash 54 | #! /bin/bash 55 | 56 | set -e 57 | set -u 58 | set -o pipefail 59 | 60 | echo "Nothing to build!" 61 | ``` 62 | 63 | 1. test.sh 64 | 65 | Sample build script for a project which doesn't require a build 66 | 67 | ```bash 68 | #! /bin/bash 69 | 70 | set -e 71 | set -u 72 | set -o pipefail 73 | 74 | echo "Nothing to test. Tests executed as part of build." 75 | ``` 76 | 77 | 1. deploy.sh - A bash script which deploys the application. The shell script can trigger Terraform/Cloudformation/AWS CDK etc. Since the shell script will run in the AWS CodeBuild docker environment, as long as the binaries are available CodeBuild will be able to execute it. 78 | 79 | Sample deployment script which installs AWS CDK and triggers the deployment 80 | 81 | ```bash 82 | #! /bin/bash 83 | 84 | set -e 85 | set -u 86 | set -o pipefail 87 | 88 | # Install CDK 89 | npm install -g aws-cdk 90 | 91 | # Install Dependencies 92 | npm install 93 | npm run build 94 | 95 | # Deploy 96 | cdk deploy --require-approval never 97 | ``` 98 | 99 | Sample deployment script which executes an AWS CloudFormation script. In this sample, the *TARGET_ENV* environment variable will be automatically set to the target environment (dev, test, prod) 100 | 101 | ```bash 102 | #! /bin/bash 103 | 104 | set -e 105 | set -u 106 | set -o pipefail 107 | 108 | aws cloudformation deploy --template-file cf_usecasecatalog.yaml --stack-name sample-cfn-stack --no-fail-on-empty-changeset --capabilities CAPABILITY_NAMED_IAM --parameter-overrides Environment=${TARGET_ENV} 109 | ``` 110 | -------------------------------------------------------------------------------- /docs/images/new_secret_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awslabs/aws-simple-cicd/1ff4a03eda6416ace2d4a945d3cd6de68f5d396d/docs/images/new_secret_01.png -------------------------------------------------------------------------------- /docs/prereq.md: -------------------------------------------------------------------------------- 1 | # Pre-Requisites 2 | 3 | This project uses AWS CDK and TypeScript. 4 | 5 | ## AWS CDK 6 | 7 | This project uses [AWS Cloud Development Kit](https://aws.amazon.com/cdk/) to provision all the resources. The CDK installation instructions are available [here](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html). 8 | 9 | Github link: 10 | -------------------------------------------------------------------------------- /lambda-helpers/email-handler/lambda.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: MIT-0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | software and associated documentation files (the "Software"), to deal in the Software 7 | without restriction, including without limitation the rights to use, copy, modify, 8 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | ''' 18 | 19 | import boto3 20 | import os 21 | import re 22 | 23 | sns = boto3.client('sns') 24 | ssm = boto3.client('ssm') 25 | ssm_root = os.environ['SSM_ROOT'] 26 | prefix = os.environ['PREFIX'] 27 | 28 | def send_codebuild_events_to_sns(message, context): 29 | 30 | status = message['detail']['build-status'] 31 | project = message['detail']['project-name'] 32 | build_id = message['detail']['build-id'] 33 | repo = re.search(rf'.*/{prefix}-(.*)', 34 | message['detail']['additional-information']['initiator'] 35 | ).group(1) 36 | 37 | ssm_key = ssm_root + '/sns-topic/' + repo + '-arn' 38 | 39 | sns_topic = ssm.get_parameter( 40 | Name=ssm_key, 41 | WithDecryption=False 42 | ) 43 | 44 | subject = "{project}: {status}".format(status=status, project=project) 45 | body = "Project: {project} \nStatus: {status} \nBuild Id: {build_id}".format(status=status, project=project, build_id=build_id) 46 | 47 | sns.publish( 48 | TopicArn=sns_topic['Parameter']['Value'], 49 | Subject=subject, 50 | Message=body 51 | ) 52 | 53 | return ('Sent a message to an Amazon SNS topic.') -------------------------------------------------------------------------------- /lambda-helpers/layers/python3_layer.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awslabs/aws-simple-cicd/1ff4a03eda6416ace2d4a945d3cd6de68f5d396d/lambda-helpers/layers/python3_layer.zip -------------------------------------------------------------------------------- /lambda-helpers/semver-handler/lambda.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: MIT-0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | software and associated documentation files (the "Software"), to deal in the Software 7 | without restriction, including without limitation the rights to use, copy, modify, 8 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | ''' 18 | import json 19 | import boto3 20 | import semver 21 | import os 22 | import traceback 23 | 24 | ssm = boto3.client('ssm') 25 | code_pipeline = boto3.client('codepipeline') 26 | ssm_root = os.environ['SSM_ROOT'] 27 | 28 | def put_job_success(job, message): 29 | """Notify CodePipeline of a successful job 30 | 31 | Args: 32 | job: The CodePipeline job ID 33 | message: A message to be logged relating to the job status 34 | 35 | Raises: 36 | Exception: Any exception thrown by .put_job_success_result() 37 | 38 | """ 39 | print('Putting job success') 40 | try: 41 | code_pipeline.put_job_success_result(jobId=job) 42 | 43 | except Exception as e: 44 | raise Exception('Put job success notification failed') 45 | 46 | def put_job_failure(job, message): 47 | """Notify CodePipeline of a failed job 48 | 49 | Args: 50 | job: The CodePipeline job ID 51 | message: A message to be logged relating to the job status 52 | 53 | Raises: 54 | Exception: Any exception thrown by .put_job_failure_result() 55 | 56 | """ 57 | print('Putting job failure') 58 | try: 59 | code_pipeline.put_job_failure_result(jobId=job, failureDetails={'message': message, 'type': 'JobFailed'}) 60 | 61 | except Exception as e: 62 | raise Exception('Put job failure notification failed') 63 | 64 | def get_user_params(job_data): 65 | """Decodes the JSON user parameters and validates the required properties. 66 | 67 | Args: 68 | job_data: The job data structure containing the UserParameters string which should be a valid JSON structure 69 | 70 | Returns: 71 | The JSON parameters decoded as a dictionary. 72 | 73 | Raises: 74 | Exception: The JSON can't be decoded or a property is missing. 75 | 76 | """ 77 | try: 78 | # Get the user parameters which contain the stack, artifact and file settings 79 | user_parameters = job_data['actionConfiguration']['configuration']['UserParameters'] 80 | decoded_parameters = json.loads(user_parameters) 81 | except Exception as e: 82 | # We're expecting the user parameters to be encoded as JSON 83 | # so we can pass multiple values. If the JSON can't be decoded 84 | # then fail the job with a helpful message. 85 | raise Exception('UserParameters could not be decoded as JSON') 86 | 87 | if 'repo' not in decoded_parameters: 88 | # Validate that the repo is provided, otherwise fail the job 89 | # with a helpful message. 90 | raise Exception('Your UserParameters JSON must include the repo name') 91 | 92 | if 'branch' not in decoded_parameters: 93 | # Validate that the repo is provided, otherwise fail the job 94 | # with a helpful message. 95 | raise Exception('Your UserParameters JSON must include the branch') 96 | 97 | return decoded_parameters 98 | 99 | def semver_handler(event, context): 100 | 101 | try: 102 | # Extract the Job ID 103 | job_id = event['CodePipeline.job']['id'] 104 | 105 | # Extract the Job Data 106 | job_data = event['CodePipeline.job']['data'] 107 | 108 | # Extract the params 109 | params = get_user_params(job_data) 110 | repo = params['repo'] 111 | branch = params['branch'] 112 | 113 | ssm_param = ssm_root + '/simple-cicd/' + repo + '/' + branch + '/version' 114 | 115 | response = ssm.get_parameter( 116 | Name=ssm_param, 117 | WithDecryption=False 118 | ) 119 | version = semver.parse_version_info(response['Parameter']['Value']) 120 | next_version = version.bump_patch() 121 | response = ssm.put_parameter( 122 | Name=ssm_param, 123 | Value=str(next_version), 124 | Type='String', 125 | Overwrite=True 126 | ) 127 | 128 | except Exception as e: 129 | # If any other exceptions which we didn't expect are raised 130 | # then fail the job and log the exception message. 131 | print('Function failed due to exception.') 132 | print(e) 133 | traceback.print_exc() 134 | put_job_failure(job_id, 'Function exception: ' + str(e)) 135 | 136 | print('Function complete.') 137 | put_job_success(job_id, 'Function complete') 138 | return "Complete." -------------------------------------------------------------------------------- /lib/cicd-s3-stack.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import * as cdk from 'aws-cdk-lib' 21 | import { Bucket } from 'aws-cdk-lib/aws-s3' 22 | import * as ssm from 'aws-cdk-lib/aws-ssm' 23 | import config from '../config/config' 24 | import { Construct } from 'constructs' 25 | 26 | interface S3StackProps extends cdk.StackProps { 27 | prefix: string, 28 | ssmRoot: string, 29 | } 30 | 31 | export class S3Stack extends cdk.Stack { 32 | constructor(scope: Construct, id: string, props: S3StackProps) { 33 | super(scope, id, props) 34 | 35 | const bucketName = `${props.prefix}-${config.sharedResources.cicdBucket}` 36 | 37 | const artifactsBucket = new Bucket(this, 'artifactsBucket', { 38 | bucketName: bucketName, 39 | versioned: false, 40 | lifecycleRules: [{ 41 | enabled: true, 42 | expiration: cdk.Duration.days(14) 43 | } 44 | ] 45 | }) 46 | 47 | new ssm.StringParameter(this, 'cicdArtifactsBucketNameParam', { 48 | description: 'Name of the CICD artifacts Bucket', 49 | parameterName: `${props.ssmRoot}/buckets/cicdArtifactsBucketName`, 50 | stringValue: artifactsBucket.bucketName 51 | }) 52 | 53 | new ssm.StringParameter(this, 'cicdArtifactsBucketArnParam', { 54 | description: 'Arn of the CICD artifacts Bucket', 55 | parameterName: `${props.ssmRoot}/buckets/cicdArtifactsBucketArn`, 56 | stringValue: artifactsBucket.bucketArn 57 | }) 58 | 59 | } 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /lib/cicd-stack.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import * as cdk from 'aws-cdk-lib' 21 | import * as ssm from 'aws-cdk-lib/aws-ssm' 22 | import * as lambda from 'aws-cdk-lib/aws-lambda' 23 | import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment' 24 | import { Bucket } from 'aws-cdk-lib/aws-s3' 25 | import { SimpleCicdPipeline } from './pipelines/simple-cicd-pipeline' 26 | import PipelineRole from './iam/pipeline-role' 27 | import { Construct } from 'constructs' 28 | import { ProjectRepo } from '../config/config' 29 | 30 | interface CicdStackProps extends cdk.StackProps { 31 | prefix: string, 32 | ssmRoot: string, 33 | cicdRoleName: string 34 | repos: Array 35 | } 36 | 37 | export class CicdStack extends cdk.Stack { 38 | constructor(scope: Construct, id: string, props: CicdStackProps) { 39 | super(scope, id, props) 40 | 41 | // Get S3 Bucket Name 42 | const artifactsBucketName = ssm.StringParameter.fromStringParameterName(this, 'artifactsBucketName', 43 | `${props.ssmRoot}/buckets/cicdArtifactsBucketName`) 44 | const artifactsBucket = Bucket.fromBucketName(this, 'artifactsBucket', artifactsBucketName.stringValue) 45 | 46 | // Push assume-cross-account-role.env to S3 47 | let ts = Date.now() 48 | new s3deploy.BucketDeployment(this, 'DeployAssumeRole', { 49 | sources: [s3deploy.Source.asset('./scripts')], 50 | destinationBucket: artifactsBucket, 51 | destinationKeyPrefix: 'admin/cross-account', 52 | metadata: { 'timestamp': ts.toString() } 53 | }); 54 | 55 | // Get Lambda email handler function 56 | const emailHandlerArn = ssm.StringParameter.fromStringParameterName(this, 'emailHandlerArn', 57 | `${props.ssmRoot}/lambda/cicd-email-handler`) 58 | const emailHandler = lambda.Function.fromFunctionArn(this, 'emailHandler', emailHandlerArn.stringValue) 59 | 60 | // Get Lambda semver handler function 61 | const semverHandlerArn = ssm.StringParameter.fromStringParameterName(this, 'semverHandlerArn', 62 | `${props.ssmRoot}/lambda/cicd-semver-handler`) 63 | const semverHandler = lambda.Function.fromFunctionArn(this, 'semverHandler', semverHandlerArn.stringValue) 64 | 65 | // Parse config.repos 66 | for (let repo of props.repos){ 67 | const pipelineName = `${props.prefix}-${repo.pipelineName}-${repo.branch}`.replace(/\/|_/g, '-') 68 | const modulePipelineRole = new PipelineRole(this, `${pipelineName}PipelineRole`) 69 | 70 | new SimpleCicdPipeline(this, `${pipelineName}`, { 71 | artifactsBucket, 72 | prefix: props.prefix, 73 | ssmRoot: props.ssmRoot, 74 | repo: repo, 75 | pipelineName, 76 | modulePipelineRole, 77 | emailHandler, 78 | semverHandler 79 | }) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/emailHandler-stack.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import * as cdk from 'aws-cdk-lib' 21 | import * as ssm from 'aws-cdk-lib/aws-ssm' 22 | import * as lambda from 'aws-cdk-lib/aws-lambda' 23 | import * as iam from 'aws-cdk-lib/aws-iam' 24 | import * as logs from 'aws-cdk-lib/aws-logs' 25 | import { ServicePrincipal } from 'aws-cdk-lib/aws-iam' 26 | import { Construct } from 'constructs' 27 | 28 | interface EmailHandlerStackProps extends cdk.StackProps { 29 | prefix: string 30 | ssmRoot: string 31 | } 32 | 33 | export class EmailHandlerStack extends cdk.Stack { 34 | constructor(scope: Construct, id: string, props: EmailHandlerStackProps) { 35 | super(scope, id, props); 36 | 37 | // Provision Lambda 38 | const emailHandler = new lambda.Function(this, 'emailHandler', { 39 | code: lambda.Code.fromAsset('./lambda-helpers/email-handler'), 40 | functionName: `${props.prefix}-cicd-emailHandler`, 41 | handler: 'lambda.send_codebuild_events_to_sns', 42 | runtime: lambda.Runtime.PYTHON_3_8, 43 | logRetention: logs.RetentionDays.TWO_WEEKS, 44 | environment: { 45 | "SSM_ROOT": props.ssmRoot, 46 | "PREFIX": props.prefix 47 | } 48 | }); 49 | 50 | emailHandler.addPermission('cloudWatchPermission', { 51 | principal: new ServicePrincipal('events.amazonaws.com') 52 | }) 53 | 54 | emailHandler.addToRolePolicy(new iam.PolicyStatement({ 55 | effect: iam.Effect.ALLOW, 56 | actions: [ 'ssm:GetParameter', 'sns:Publish' ], 57 | resources: [ '*' ] 58 | })); 59 | 60 | new ssm.StringParameter(this, 'EmailHandlerArn', { 61 | description: 'Email Handler Lambda Function Arn', 62 | parameterName: `${props.ssmRoot}/lambda/cicd-email-handler`, 63 | stringValue: emailHandler.functionArn 64 | }); 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/iam/code-build-role.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | import * as iam from 'aws-cdk-lib/aws-iam' 20 | import { Construct } from 'constructs' 21 | import config from '../../config/config' 22 | import { StageName } from '../../config/config' 23 | 24 | export interface CodeBuildRoleProps { 25 | stageName?: StageName 26 | } 27 | 28 | export default class CodeBuildRole extends iam.Role { 29 | constructor(scope: Construct, name: string, props: CodeBuildRoleProps = {}) { 30 | const { stageName, ...rest } = props 31 | super(scope, name, { 32 | ...rest, 33 | assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com') 34 | }) 35 | 36 | if (stageName) { 37 | this.addToPolicy(new iam.PolicyStatement({ 38 | effect: iam.Effect.ALLOW, 39 | actions: ['sts:AssumeRole'], 40 | resources: [`arn:aws:iam::${config.accountIds[stageName]}:role/${config.deployment['cicdRoleName']}`] 41 | })) 42 | } 43 | 44 | this.addToPolicy( 45 | new iam.PolicyStatement({ 46 | effect: iam.Effect.ALLOW, 47 | actions:[ 48 | 'logs:CreateLogGroup', 49 | 'logs:CreateLogStream', 50 | 'logs:DeleteLogGroup', 51 | 'logs:PutLogEvents' 52 | ], 53 | resources: [`arn:aws:logs:${config.deployment.region}:*:log-group:*`] 54 | }) 55 | ) // TODO - specific log groups 56 | 57 | this.addToPolicy( 58 | new iam.PolicyStatement({ 59 | effect: iam.Effect.ALLOW, 60 | actions:[ 61 | 'ecr:Describe*', 62 | 'ecr:List*', 63 | 'ecr:Get*', 64 | 'ecr:Put*', 65 | 'ecr:UploadLayerPart', 66 | 'ecr:InitiateLayerUpload', 67 | 'ecr:CompleteLayerUpload', 68 | 'ecr:BatchCheckLayerAvailability', 69 | 'ssm:GetParameters' 70 | ], 71 | resources: ['*'] 72 | }) 73 | ) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/iam/pipeline-role.ts: -------------------------------------------------------------------------------- 1 | import * as iam from 'aws-cdk-lib/aws-iam' 2 | import { Construct } from 'constructs' 3 | 4 | export interface PipelineRoleProps {} 5 | 6 | export default class PipelineRole extends iam.Role { 7 | constructor(scope: Construct, name: string, props: PipelineRoleProps = {}) { 8 | super(scope, name, { 9 | ...props, 10 | assumedBy: new iam.ServicePrincipal('codepipeline.amazonaws.com') 11 | }) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/pipelines/simple-cicd-pipeline.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import { Pipeline, Artifact } from 'aws-cdk-lib/aws-codepipeline' 21 | import { SecretValue } from 'aws-cdk-lib' 22 | import { Construct } from 'constructs' 23 | import { IBucket } from 'aws-cdk-lib/aws-s3' 24 | import { 25 | CodeBuildAction, 26 | CodeCommitSourceAction, 27 | ManualApprovalAction, 28 | LambdaInvokeAction, 29 | GitHubSourceAction 30 | } from 'aws-cdk-lib/aws-codepipeline-actions' 31 | import config from '../../config/config' 32 | import { StageName, TriggerType, ProjectRepo } from '../../config/config'; 33 | import CodeBuildRole from '../iam/code-build-role' 34 | import { DeployProject } from '../projects/deploy-project' 35 | import { Role } from 'aws-cdk-lib/aws-iam' 36 | import { IFunction } from 'aws-cdk-lib/aws-lambda' 37 | import { Repository } from 'aws-cdk-lib/aws-codecommit' 38 | import { BuildProject } from '../projects/build-project' 39 | import { TestProject } from '../projects/test-project' 40 | import { Rule, Schedule } from 'aws-cdk-lib/aws-events' 41 | import * as ssm from 'aws-cdk-lib/aws-ssm'; 42 | import * as sns from 'aws-cdk-lib/aws-sns'; 43 | import * as targets from 'aws-cdk-lib/aws-events-targets'; 44 | 45 | export interface SimpleCicdPipelineProps { 46 | artifactsBucket: IBucket 47 | prefix: string 48 | ssmRoot: string 49 | repo: ProjectRepo 50 | pipelineName: string, 51 | modulePipelineRole: Role 52 | emailHandler: IFunction 53 | semverHandler: IFunction 54 | } 55 | 56 | export class SimpleCicdPipeline extends Pipeline { 57 | constructor(scope: Construct, id: string, props: SimpleCicdPipelineProps) { 58 | const { 59 | artifactsBucket, 60 | prefix, 61 | ssmRoot, 62 | repo, 63 | pipelineName, 64 | modulePipelineRole, 65 | emailHandler, 66 | semverHandler, 67 | ...rest 68 | } = props 69 | 70 | super(scope, id, { 71 | pipelineName, 72 | artifactBucket: artifactsBucket, 73 | role: modulePipelineRole, 74 | ...rest 75 | }) 76 | 77 | let repoName = repo.repository 78 | let repoBranch = repo.branch 79 | 80 | // Provision SNS Topic for notifications 81 | const notificationTopic = new sns.Topic(this, 'Topic', { 82 | displayName: `${pipelineName}-cicd-topic` , 83 | topicName: `${pipelineName}-cicd-topic` 84 | }) 85 | 86 | new ssm.StringParameter(this, 'SnsTopicArn', { 87 | description: 'CICD SNS Topic Arn', 88 | parameterName: `${ssmRoot}/sns-topic/${repoName}-${repoBranch}-arn`, 89 | stringValue: notificationTopic.topicArn 90 | }) 91 | 92 | // Source Control Stage (CodeCommit) 93 | const sourceOutputArtifact = new Artifact('SourceArtifact') 94 | switch (repo.type) { 95 | case TriggerType.CodeCommit: { 96 | const codeCommitRepo = Repository.fromRepositoryName( 97 | scope, 98 | `${repoName}${repoBranch}CodeCommitRepo`, 99 | repoName 100 | ) 101 | 102 | codeCommitRepo.onCommit('OnCommit', { 103 | target: new targets.CodePipeline(this), 104 | branches: [`${repoBranch}`] 105 | }) 106 | 107 | const sourceAction = new CodeCommitSourceAction({ 108 | repository: codeCommitRepo, 109 | branch: repoBranch, 110 | output: sourceOutputArtifact, 111 | actionName: 'Source' 112 | }) 113 | 114 | this.addStage({ 115 | stageName: 'Source', 116 | actions: [sourceAction] 117 | }) 118 | break 119 | } 120 | case TriggerType.GitHub: { 121 | const oauth = SecretValue.secretsManager(config.deployment['githubSecret']) 122 | 123 | const sourceAction = new GitHubSourceAction({ 124 | actionName: 'Source', 125 | oauthToken: oauth, 126 | owner: repo.owner, 127 | repo: repoName, 128 | branch: repoBranch, 129 | output: sourceOutputArtifact, 130 | }) 131 | 132 | this.addStage({ 133 | stageName: 'Source', 134 | actions: [sourceAction] 135 | }) 136 | break 137 | } 138 | } 139 | 140 | 141 | // Building Stage 142 | const buildOutputArtifact = new Artifact('BuildArtifact') 143 | const buildRole = new CodeBuildRole(this, 'buildRole') 144 | 145 | const buildProject = new BuildProject(this, `${pipelineName}-build`, { 146 | repoName: repoName, 147 | role: buildRole, 148 | bucketArn: artifactsBucket.bucketArn, 149 | bucketName: artifactsBucket.bucketName 150 | }) 151 | 152 | buildProject.onStateChange('build', { 153 | target: new targets.LambdaFunction(emailHandler) 154 | }) 155 | 156 | const buildAction = new CodeBuildAction ({ 157 | actionName: 'Build', 158 | outputs: [buildOutputArtifact], 159 | input: sourceOutputArtifact, 160 | project: buildProject 161 | }) 162 | 163 | const semverAction = new LambdaInvokeAction({ 164 | actionName: 'SemverLambda', 165 | lambda: semverHandler, 166 | userParameters: { 167 | 'repo': repoName, 168 | 'branch': repoBranch 169 | }, 170 | runOrder: 20 171 | }); 172 | 173 | this.addStage({ 174 | stageName: 'Build', 175 | actions: [buildAction, semverAction] 176 | }) 177 | 178 | // Push SemVer to Parameter Store 179 | let semverParam = `${ssmRoot}/simple-cicd/${repoName}/${repoBranch}/version` 180 | new ssm.StringParameter(this, `${repoName}${repoBranch}Version`, { 181 | description: `Version number of ${repoName}/${repoBranch}`, 182 | parameterName: semverParam, 183 | stringValue: '0.1.0' 184 | }) 185 | 186 | // Testing Stage 187 | const testOutputArtifact = new Artifact('TestArtifact') 188 | const testRole = new CodeBuildRole(this, 'testRole') 189 | 190 | const testProject = new TestProject(this, `${pipelineName}-test`, { 191 | repoName: repoName, 192 | role: testRole, 193 | bucketArn: artifactsBucket.bucketArn, 194 | bucketName: artifactsBucket.bucketName, 195 | semverParameter: semverParam 196 | }) 197 | 198 | testProject.onStateChange('test', { 199 | target: new targets.LambdaFunction(emailHandler) 200 | }) 201 | 202 | const testAction = new CodeBuildAction ({ 203 | actionName: 'Test', 204 | outputs: [testOutputArtifact], 205 | input: buildOutputArtifact, 206 | project: testProject 207 | }) 208 | 209 | this.addStage({ 210 | stageName: 'Test', 211 | actions: [testAction] 212 | }) 213 | 214 | // Target defaults 215 | // TODO: Make this user configurable 216 | let targetEnvs = [StageName.dev, StageName.test, StageName.prod] 217 | if (repo.targets) { 218 | targetEnvs = repo.targets 219 | } 220 | 221 | // Deploying Stage (One stage per target environment) 222 | targetEnvs.forEach((stageName: StageName) => { 223 | 224 | // Only add stage if accountId is set 225 | if (config.accountIds[stageName]) { 226 | const deployRole = new CodeBuildRole(this, `${stageName}DeployRole`, { stageName }) 227 | const deployProject = new DeployProject( 228 | this, 229 | `${pipelineName}-${stageName}-deploy`, 230 | { 231 | repoName: repoName, 232 | stageName: stageName, 233 | role: deployRole, 234 | bucketArn: artifactsBucket.bucketArn, 235 | bucketName: artifactsBucket.bucketName, 236 | semverParameter: semverParam 237 | } 238 | ) 239 | deployProject.onStateChange('deploy', { 240 | target: new targets.LambdaFunction(emailHandler) 241 | }) 242 | 243 | if (stageName == 'prod') { 244 | this.addStage({ 245 | stageName: 'prod-approval', 246 | actions: [new ManualApprovalAction({ 247 | actionName: 'Promote' 248 | })] 249 | }) 250 | } 251 | 252 | const moduleDeployOutputArtifact = new Artifact() 253 | const moduleDeployAction = new CodeBuildAction({ 254 | actionName: 'Deploy', 255 | input: testOutputArtifact, 256 | outputs: [moduleDeployOutputArtifact], 257 | project: deployProject, 258 | role: modulePipelineRole 259 | }) 260 | this.addStage({ 261 | stageName: `Deploy-to-${stageName}-environment`, 262 | actions: [moduleDeployAction] 263 | }) 264 | } 265 | }) 266 | 267 | if (repo.cron) { 268 | const cwRule = new Rule(this, `${pipelineName}-cronTrigger`, { 269 | ruleName: `${pipelineName}-trigger`, 270 | enabled: true, 271 | schedule: Schedule.expression(`cron(${repo.cron})`) 272 | }) 273 | cwRule.addTarget(new targets.CodePipeline(this)) 274 | } 275 | 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /lib/projects/build-project-environment.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | import { BuildEnvironmentVariableType, ComputeType, 20 | LinuxBuildImage } from 'aws-cdk-lib/aws-codebuild' 21 | 22 | export const defaultEnvironment = { 23 | buildImage: LinuxBuildImage.STANDARD_4_0, 24 | computeType: ComputeType.SMALL, 25 | privileged: true 26 | } 27 | 28 | export function projectEnvironmentVars(props: { 29 | repoName: string 30 | bucketName: string 31 | bucketArn: string 32 | }) { 33 | const siteVars: any = {} 34 | 35 | return { 36 | ARTIFACTS_BUCKET_NAME: { 37 | type: BuildEnvironmentVariableType.PLAINTEXT, 38 | value: props.bucketName 39 | }, 40 | ARTIFACTS_BUCKET_ARN: { 41 | type: BuildEnvironmentVariableType.PLAINTEXT, 42 | value: props.bucketArn 43 | }, 44 | REPO_NAME: { 45 | type: BuildEnvironmentVariableType.PLAINTEXT, 46 | value: props.repoName 47 | }, 48 | ...siteVars 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/projects/build-project.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import { Construct } from 'constructs'; 21 | import { PipelineProject, ProjectProps, BuildSpec} from 'aws-cdk-lib/aws-codebuild' 22 | import { defaultEnvironment } from './build-project-environment' 23 | import { projectEnvironmentVars } from './build-project-environment' 24 | import { Role } from 'aws-cdk-lib/aws-iam' 25 | 26 | export interface BuildProjectProps extends ProjectProps { 27 | repoName: string 28 | bucketName: string 29 | bucketArn: string 30 | role: Role 31 | } 32 | 33 | export class BuildProject extends PipelineProject { 34 | constructor(scope: Construct, id: string, props: BuildProjectProps) { 35 | const { repoName, bucketName, bucketArn } = props 36 | super(scope, id, { 37 | projectName: id, 38 | role: props.role, 39 | environment: defaultEnvironment, 40 | environmentVariables: projectEnvironmentVars({ repoName, bucketName, bucketArn }), 41 | buildSpec: BuildSpec.fromObject({ 42 | version: '0.2', 43 | env: { 44 | shell: 'bash' 45 | }, 46 | phases: { 47 | install: { 48 | 'runtime-versions': { 49 | nodejs: '10' 50 | } 51 | }, 52 | build: { 53 | commands: [ 54 | 'bash ${CODEBUILD_SRC_DIR}/scripts/build.sh' 55 | ] 56 | } 57 | }, 58 | artifacts: { 59 | files: '**/*' 60 | } 61 | }) 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/projects/deploy-project-environment.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import config from '../../config/config' 21 | import { StageName } from '../../config/config'; 22 | import { BuildEnvironmentVariableType, ComputeType, 23 | LinuxBuildImage } from 'aws-cdk-lib/aws-codebuild' 24 | 25 | export const defaultEnvironment = { 26 | buildImage: LinuxBuildImage.STANDARD_4_0, 27 | computeType: ComputeType.SMALL, 28 | privileged: true 29 | } 30 | 31 | export function projectEnvironmentVars(props: { 32 | stageName: StageName 33 | repoName: string 34 | bucketName: string 35 | bucketArn: string 36 | }) { 37 | const siteVars: any = {} 38 | 39 | return { 40 | TARGET_ENV: { 41 | type: BuildEnvironmentVariableType.PLAINTEXT, 42 | value: props.stageName 43 | }, 44 | TARGET_ACCOUNT_ID: { 45 | type: BuildEnvironmentVariableType.PLAINTEXT, 46 | value: `${config.accountIds[props.stageName]}` 47 | }, 48 | CROSS_ACCOUNT_ROLE: { 49 | type: BuildEnvironmentVariableType.PLAINTEXT, 50 | value: config.deployment['cicdRoleName'] 51 | }, 52 | REPO_NAME: { 53 | type: BuildEnvironmentVariableType.PLAINTEXT, 54 | value: props.repoName 55 | }, 56 | TARGET_REGION: { 57 | type: BuildEnvironmentVariableType.PLAINTEXT, 58 | value: `${config.defaultRegions[props.stageName]}` 59 | }, 60 | ARTIFACTS_BUCKET_NAME: { 61 | type: BuildEnvironmentVariableType.PLAINTEXT, 62 | value: props.bucketName 63 | }, 64 | ARTIFACTS_BUCKET_ARN: { 65 | type: BuildEnvironmentVariableType.PLAINTEXT, 66 | value: props.bucketArn 67 | }, 68 | ...siteVars 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/projects/deploy-project.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | 20 | import { PipelineProject, BuildSpec } from 'aws-cdk-lib/aws-codebuild' 21 | import { Construct } from 'constructs'; 22 | import { defaultEnvironment } from './deploy-project-environment' 23 | import { projectEnvironmentVars } from './deploy-project-environment' 24 | import { Role } from 'aws-cdk-lib/aws-iam' 25 | import { StageName } from '../../config/config'; 26 | 27 | export interface DeployProjectProps { 28 | repoName: string 29 | stageName: StageName 30 | bucketName: string 31 | bucketArn: string 32 | role: Role 33 | semverParameter: string 34 | } 35 | 36 | export class DeployProject extends PipelineProject { 37 | constructor(scope: Construct, id: string, props: DeployProjectProps) { 38 | const { repoName, stageName, bucketName, bucketArn } = props 39 | super(scope, id, { 40 | projectName: id, 41 | role: props.role, 42 | environment: defaultEnvironment, 43 | environmentVariables: projectEnvironmentVars({ stageName, repoName, bucketName, bucketArn }), 44 | buildSpec: BuildSpec.fromObject({ 45 | version: '0.2', 46 | env: { 47 | shell: 'bash', 48 | 'parameter-store': { 49 | SEMVER: props.semverParameter 50 | } 51 | }, 52 | phases: { 53 | install: { 54 | 'runtime-versions': { 55 | nodejs: '10' 56 | } 57 | }, 58 | build: { 59 | commands: [ 60 | 'if [ ! -f "${CODEBUILD_SRC_DIR}/scripts/assume-cross-account-role.env" ]; then echo "assume-cross-account-this.role.env not found in repo" && aws s3 cp s3://${ARTIFACTS_BUCKET_NAME}/admin/cross-account/assume-cross-account-role.env ${CODEBUILD_SRC_DIR}/scripts/; else echo "Overriding assume-cross-account-role.env from repo"; fi', 61 | '. ${CODEBUILD_SRC_DIR}/scripts/assume-cross-account-role.env', 62 | 'bash ${CODEBUILD_SRC_DIR}/scripts/deploy.sh' 63 | ] 64 | } 65 | } 66 | }) 67 | }) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/projects/test-project.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | import { Construct } from 'constructs'; 20 | import { PipelineProject, ProjectProps, BuildSpec} from 'aws-cdk-lib/aws-codebuild' 21 | import { defaultEnvironment } from './build-project-environment' 22 | import { projectEnvironmentVars } from './build-project-environment' 23 | import { Role } from 'aws-cdk-lib/aws-iam' 24 | 25 | export interface BuildProjectProps extends ProjectProps { 26 | repoName: string 27 | bucketName: string 28 | bucketArn: string 29 | role: Role 30 | semverParameter: string 31 | } 32 | 33 | export class TestProject extends PipelineProject { 34 | constructor(scope: Construct, id: string, props: BuildProjectProps) { 35 | const { repoName, bucketName, bucketArn } = props 36 | super(scope, id, { 37 | projectName: id, 38 | role: props.role, 39 | environment: defaultEnvironment, 40 | environmentVariables: projectEnvironmentVars({ repoName, bucketName, bucketArn }), 41 | buildSpec: BuildSpec.fromObject({ 42 | version: '0.2', 43 | env: { 44 | shell: 'bash', 45 | 'parameter-store': { 46 | SEMVER: props.semverParameter 47 | } 48 | }, 49 | phases: { 50 | install: { 51 | 'runtime-versions': { 52 | nodejs: '10' 53 | } 54 | }, 55 | build: { 56 | commands: [ 57 | 'bash ${CODEBUILD_SRC_DIR}/scripts/test.sh' 58 | ] 59 | } 60 | }, 61 | artifacts: { 62 | files: '**/*' 63 | } 64 | }) 65 | }) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/semverHandler-stack.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | import * as cdk from 'aws-cdk-lib' 20 | import * as ssm from 'aws-cdk-lib/aws-ssm' 21 | import * as lambda from 'aws-cdk-lib/aws-lambda' 22 | import * as iam from 'aws-cdk-lib/aws-iam' 23 | import * as logs from 'aws-cdk-lib/aws-logs' 24 | import { ServicePrincipal } from 'aws-cdk-lib/aws-iam' 25 | import { Construct } from 'constructs' 26 | 27 | interface SemverHandlerStackProps extends cdk.StackProps { 28 | prefix: string 29 | ssmRoot: string 30 | } 31 | 32 | export class SemverHandlerStack extends cdk.Stack { 33 | constructor(scope: Construct, id: string, props: SemverHandlerStackProps) { 34 | super(scope, id, props); 35 | 36 | // Provision Lambda Layer 37 | const pythonLayer = new lambda.LayerVersion(this, 'python3Layer', { 38 | code: lambda.Code.fromAsset('./lambda-helpers/layers/python3_layer.zip'), 39 | compatibleRuntimes: [lambda.Runtime.PYTHON_3_6, lambda.Runtime.PYTHON_3_7, lambda.Runtime.PYTHON_3_8], 40 | description: 'A Python layer with Semver', 41 | layerVersionName: `${props.prefix}-cicd-python3-layer` 42 | }); 43 | 44 | // Provision Lambda 45 | const semverHandler = new lambda.Function(this, 'semverHandler', { 46 | code: lambda.Code.fromAsset('./lambda-helpers/semver-handler'), 47 | functionName: `${props.prefix}-cicd-semverHandler`, 48 | handler: 'lambda.semver_handler', 49 | runtime: lambda.Runtime.PYTHON_3_8, 50 | layers: [ pythonLayer ], 51 | logRetention: logs.RetentionDays.TWO_WEEKS, 52 | environment: { 53 | "SSM_ROOT": props.ssmRoot 54 | } 55 | }); 56 | 57 | semverHandler.addPermission('codePipelinePermission', { 58 | principal: new ServicePrincipal('codepipeline.amazonaws.com') 59 | }) 60 | 61 | semverHandler.addToRolePolicy(new iam.PolicyStatement({ 62 | effect: iam.Effect.ALLOW, 63 | actions: [ 'ssm:GetParameter', 'ssm:PutParameter', 'codepipeline:PutJobFailureResult', 'codepipeline:PutJobSuccessResult' ], 64 | resources: [ '*' ] 65 | })); 66 | 67 | new ssm.StringParameter(this, 'SemverHandlerArn', { 68 | description: 'Semver Handler Lambda Function Arn', 69 | parameterName: `${props.ssmRoot}/lambda/cicd-semver-handler`, 70 | stringValue: semverHandler.functionArn 71 | }); 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cicd", 3 | "version": "0.2.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "cicd", 9 | "version": "0.2.0", 10 | "dependencies": { 11 | "aws-cdk-lib": "^2.27.0", 12 | "constructs": "^10.0.0", 13 | "source-map-support": "^0.5.19" 14 | }, 15 | "bin": { 16 | "cicd": "bin/cicd.js" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^17.0.40", 20 | "aws-cdk": "^2.27.0", 21 | "aws-sdk": "^2.1354.0", 22 | "husky": "^6.0.0", 23 | "tsort": "0.0.1", 24 | "typescript": "^4.7.3" 25 | } 26 | }, 27 | "node_modules/@aws-cdk/asset-awscli-v1": { 28 | "version": "2.2.135", 29 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.135.tgz", 30 | "integrity": "sha512-fdkrAjs/RQ9AmapA09cY5Gr9A+N+zYvUj0fuLYqeXjpl2BxLIpvkyfsL9IBxI/9lAUHHriLj6z84N6wZCgHscg==" 31 | }, 32 | "node_modules/@aws-cdk/asset-kubectl-v20": { 33 | "version": "2.1.1", 34 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.1.tgz", 35 | "integrity": "sha512-U1ntiX8XiMRRRH5J1IdC+1t5CE89015cwyt5U63Cpk0GnMlN5+h9WsWMlKlPXZR4rdq/m806JRlBMRpBUB2Dhw==" 36 | }, 37 | "node_modules/@aws-cdk/asset-node-proxy-agent-v5": { 38 | "version": "2.0.111", 39 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v5/-/asset-node-proxy-agent-v5-2.0.111.tgz", 40 | "integrity": "sha512-qfHTsN6E94gpAjc833KRoonZ+hN/n3IAvU5/LW1CLV0WGx56phThXo7rgUusOXI/Yna7K8FPgcmMDwSq0hD3WA==" 41 | }, 42 | "node_modules/@types/node": { 43 | "version": "17.0.45", 44 | "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", 45 | "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", 46 | "dev": true 47 | }, 48 | "node_modules/available-typed-arrays": { 49 | "version": "1.0.5", 50 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", 51 | "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", 52 | "dev": true, 53 | "engines": { 54 | "node": ">= 0.4" 55 | }, 56 | "funding": { 57 | "url": "https://github.com/sponsors/ljharb" 58 | } 59 | }, 60 | "node_modules/aws-cdk": { 61 | "version": "2.73.0", 62 | "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.73.0.tgz", 63 | "integrity": "sha512-4ZnY+OS83goCzv+1sCEpNTNiXWjY6KBzic2RNUObzpHjUskRSwUCtaeiv6OyZ55DZoP0tneAmWIBXHfixJ7iQw==", 64 | "dev": true, 65 | "bin": { 66 | "cdk": "bin/cdk" 67 | }, 68 | "engines": { 69 | "node": ">= 14.15.0" 70 | }, 71 | "optionalDependencies": { 72 | "fsevents": "2.3.2" 73 | } 74 | }, 75 | "node_modules/aws-cdk-lib": { 76 | "version": "2.73.0", 77 | "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.73.0.tgz", 78 | "integrity": "sha512-r9CUe3R7EThr9U0Eb7kQCK4Ee34TDeMH+bonvGD9rNRRTYDauvAgNCsx4DZYYksPrXLRzWjzVbuXAHaDDzWt+A==", 79 | "bundleDependencies": [ 80 | "@balena/dockerignore", 81 | "case", 82 | "fs-extra", 83 | "ignore", 84 | "jsonschema", 85 | "minimatch", 86 | "punycode", 87 | "semver", 88 | "table", 89 | "yaml" 90 | ], 91 | "dependencies": { 92 | "@aws-cdk/asset-awscli-v1": "^2.2.97", 93 | "@aws-cdk/asset-kubectl-v20": "^2.1.1", 94 | "@aws-cdk/asset-node-proxy-agent-v5": "^2.0.77", 95 | "@balena/dockerignore": "^1.0.2", 96 | "case": "1.6.3", 97 | "fs-extra": "^9.1.0", 98 | "ignore": "^5.2.4", 99 | "jsonschema": "^1.4.1", 100 | "minimatch": "^3.1.2", 101 | "punycode": "^2.3.0", 102 | "semver": "^7.3.8", 103 | "table": "^6.8.1", 104 | "yaml": "1.10.2" 105 | }, 106 | "engines": { 107 | "node": ">= 14.15.0" 108 | }, 109 | "peerDependencies": { 110 | "constructs": "^10.0.0" 111 | } 112 | }, 113 | "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { 114 | "version": "1.0.2", 115 | "inBundle": true, 116 | "license": "Apache-2.0" 117 | }, 118 | "node_modules/aws-cdk-lib/node_modules/ajv": { 119 | "version": "8.12.0", 120 | "inBundle": true, 121 | "license": "MIT", 122 | "dependencies": { 123 | "fast-deep-equal": "^3.1.1", 124 | "json-schema-traverse": "^1.0.0", 125 | "require-from-string": "^2.0.2", 126 | "uri-js": "^4.2.2" 127 | }, 128 | "funding": { 129 | "type": "github", 130 | "url": "https://github.com/sponsors/epoberezkin" 131 | } 132 | }, 133 | "node_modules/aws-cdk-lib/node_modules/ansi-regex": { 134 | "version": "5.0.1", 135 | "inBundle": true, 136 | "license": "MIT", 137 | "engines": { 138 | "node": ">=8" 139 | } 140 | }, 141 | "node_modules/aws-cdk-lib/node_modules/ansi-styles": { 142 | "version": "4.3.0", 143 | "inBundle": true, 144 | "license": "MIT", 145 | "dependencies": { 146 | "color-convert": "^2.0.1" 147 | }, 148 | "engines": { 149 | "node": ">=8" 150 | }, 151 | "funding": { 152 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 153 | } 154 | }, 155 | "node_modules/aws-cdk-lib/node_modules/astral-regex": { 156 | "version": "2.0.0", 157 | "inBundle": true, 158 | "license": "MIT", 159 | "engines": { 160 | "node": ">=8" 161 | } 162 | }, 163 | "node_modules/aws-cdk-lib/node_modules/at-least-node": { 164 | "version": "1.0.0", 165 | "inBundle": true, 166 | "license": "ISC", 167 | "engines": { 168 | "node": ">= 4.0.0" 169 | } 170 | }, 171 | "node_modules/aws-cdk-lib/node_modules/balanced-match": { 172 | "version": "1.0.2", 173 | "inBundle": true, 174 | "license": "MIT" 175 | }, 176 | "node_modules/aws-cdk-lib/node_modules/brace-expansion": { 177 | "version": "1.1.11", 178 | "inBundle": true, 179 | "license": "MIT", 180 | "dependencies": { 181 | "balanced-match": "^1.0.0", 182 | "concat-map": "0.0.1" 183 | } 184 | }, 185 | "node_modules/aws-cdk-lib/node_modules/case": { 186 | "version": "1.6.3", 187 | "inBundle": true, 188 | "license": "(MIT OR GPL-3.0-or-later)", 189 | "engines": { 190 | "node": ">= 0.8.0" 191 | } 192 | }, 193 | "node_modules/aws-cdk-lib/node_modules/color-convert": { 194 | "version": "2.0.1", 195 | "inBundle": true, 196 | "license": "MIT", 197 | "dependencies": { 198 | "color-name": "~1.1.4" 199 | }, 200 | "engines": { 201 | "node": ">=7.0.0" 202 | } 203 | }, 204 | "node_modules/aws-cdk-lib/node_modules/color-name": { 205 | "version": "1.1.4", 206 | "inBundle": true, 207 | "license": "MIT" 208 | }, 209 | "node_modules/aws-cdk-lib/node_modules/concat-map": { 210 | "version": "0.0.1", 211 | "inBundle": true, 212 | "license": "MIT" 213 | }, 214 | "node_modules/aws-cdk-lib/node_modules/emoji-regex": { 215 | "version": "8.0.0", 216 | "inBundle": true, 217 | "license": "MIT" 218 | }, 219 | "node_modules/aws-cdk-lib/node_modules/fast-deep-equal": { 220 | "version": "3.1.3", 221 | "inBundle": true, 222 | "license": "MIT" 223 | }, 224 | "node_modules/aws-cdk-lib/node_modules/fs-extra": { 225 | "version": "9.1.0", 226 | "inBundle": true, 227 | "license": "MIT", 228 | "dependencies": { 229 | "at-least-node": "^1.0.0", 230 | "graceful-fs": "^4.2.0", 231 | "jsonfile": "^6.0.1", 232 | "universalify": "^2.0.0" 233 | }, 234 | "engines": { 235 | "node": ">=10" 236 | } 237 | }, 238 | "node_modules/aws-cdk-lib/node_modules/graceful-fs": { 239 | "version": "4.2.10", 240 | "inBundle": true, 241 | "license": "ISC" 242 | }, 243 | "node_modules/aws-cdk-lib/node_modules/ignore": { 244 | "version": "5.2.4", 245 | "inBundle": true, 246 | "license": "MIT", 247 | "engines": { 248 | "node": ">= 4" 249 | } 250 | }, 251 | "node_modules/aws-cdk-lib/node_modules/is-fullwidth-code-point": { 252 | "version": "3.0.0", 253 | "inBundle": true, 254 | "license": "MIT", 255 | "engines": { 256 | "node": ">=8" 257 | } 258 | }, 259 | "node_modules/aws-cdk-lib/node_modules/json-schema-traverse": { 260 | "version": "1.0.0", 261 | "inBundle": true, 262 | "license": "MIT" 263 | }, 264 | "node_modules/aws-cdk-lib/node_modules/jsonfile": { 265 | "version": "6.1.0", 266 | "inBundle": true, 267 | "license": "MIT", 268 | "dependencies": { 269 | "universalify": "^2.0.0" 270 | }, 271 | "optionalDependencies": { 272 | "graceful-fs": "^4.1.6" 273 | } 274 | }, 275 | "node_modules/aws-cdk-lib/node_modules/jsonschema": { 276 | "version": "1.4.1", 277 | "inBundle": true, 278 | "license": "MIT", 279 | "engines": { 280 | "node": "*" 281 | } 282 | }, 283 | "node_modules/aws-cdk-lib/node_modules/lodash.truncate": { 284 | "version": "4.4.2", 285 | "inBundle": true, 286 | "license": "MIT" 287 | }, 288 | "node_modules/aws-cdk-lib/node_modules/lru-cache": { 289 | "version": "6.0.0", 290 | "inBundle": true, 291 | "license": "ISC", 292 | "dependencies": { 293 | "yallist": "^4.0.0" 294 | }, 295 | "engines": { 296 | "node": ">=10" 297 | } 298 | }, 299 | "node_modules/aws-cdk-lib/node_modules/minimatch": { 300 | "version": "3.1.2", 301 | "inBundle": true, 302 | "license": "ISC", 303 | "dependencies": { 304 | "brace-expansion": "^1.1.7" 305 | }, 306 | "engines": { 307 | "node": "*" 308 | } 309 | }, 310 | "node_modules/aws-cdk-lib/node_modules/punycode": { 311 | "version": "2.3.0", 312 | "inBundle": true, 313 | "license": "MIT", 314 | "engines": { 315 | "node": ">=6" 316 | } 317 | }, 318 | "node_modules/aws-cdk-lib/node_modules/require-from-string": { 319 | "version": "2.0.2", 320 | "inBundle": true, 321 | "license": "MIT", 322 | "engines": { 323 | "node": ">=0.10.0" 324 | } 325 | }, 326 | "node_modules/aws-cdk-lib/node_modules/semver": { 327 | "version": "7.3.8", 328 | "inBundle": true, 329 | "license": "ISC", 330 | "dependencies": { 331 | "lru-cache": "^6.0.0" 332 | }, 333 | "bin": { 334 | "semver": "bin/semver.js" 335 | }, 336 | "engines": { 337 | "node": ">=10" 338 | } 339 | }, 340 | "node_modules/aws-cdk-lib/node_modules/slice-ansi": { 341 | "version": "4.0.0", 342 | "inBundle": true, 343 | "license": "MIT", 344 | "dependencies": { 345 | "ansi-styles": "^4.0.0", 346 | "astral-regex": "^2.0.0", 347 | "is-fullwidth-code-point": "^3.0.0" 348 | }, 349 | "engines": { 350 | "node": ">=10" 351 | }, 352 | "funding": { 353 | "url": "https://github.com/chalk/slice-ansi?sponsor=1" 354 | } 355 | }, 356 | "node_modules/aws-cdk-lib/node_modules/string-width": { 357 | "version": "4.2.3", 358 | "inBundle": true, 359 | "license": "MIT", 360 | "dependencies": { 361 | "emoji-regex": "^8.0.0", 362 | "is-fullwidth-code-point": "^3.0.0", 363 | "strip-ansi": "^6.0.1" 364 | }, 365 | "engines": { 366 | "node": ">=8" 367 | } 368 | }, 369 | "node_modules/aws-cdk-lib/node_modules/strip-ansi": { 370 | "version": "6.0.1", 371 | "inBundle": true, 372 | "license": "MIT", 373 | "dependencies": { 374 | "ansi-regex": "^5.0.1" 375 | }, 376 | "engines": { 377 | "node": ">=8" 378 | } 379 | }, 380 | "node_modules/aws-cdk-lib/node_modules/table": { 381 | "version": "6.8.1", 382 | "inBundle": true, 383 | "license": "BSD-3-Clause", 384 | "dependencies": { 385 | "ajv": "^8.0.1", 386 | "lodash.truncate": "^4.4.2", 387 | "slice-ansi": "^4.0.0", 388 | "string-width": "^4.2.3", 389 | "strip-ansi": "^6.0.1" 390 | }, 391 | "engines": { 392 | "node": ">=10.0.0" 393 | } 394 | }, 395 | "node_modules/aws-cdk-lib/node_modules/universalify": { 396 | "version": "2.0.0", 397 | "inBundle": true, 398 | "license": "MIT", 399 | "engines": { 400 | "node": ">= 10.0.0" 401 | } 402 | }, 403 | "node_modules/aws-cdk-lib/node_modules/uri-js": { 404 | "version": "4.4.1", 405 | "inBundle": true, 406 | "license": "BSD-2-Clause", 407 | "dependencies": { 408 | "punycode": "^2.1.0" 409 | } 410 | }, 411 | "node_modules/aws-cdk-lib/node_modules/yallist": { 412 | "version": "4.0.0", 413 | "inBundle": true, 414 | "license": "ISC" 415 | }, 416 | "node_modules/aws-cdk-lib/node_modules/yaml": { 417 | "version": "1.10.2", 418 | "inBundle": true, 419 | "license": "ISC", 420 | "engines": { 421 | "node": ">= 6" 422 | } 423 | }, 424 | "node_modules/aws-sdk": { 425 | "version": "2.1354.0", 426 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1354.0.tgz", 427 | "integrity": "sha512-3aDxvyuOqMB9DqJguCq6p8momdsz0JR1axwkWOOCzHA7a35+Bw+WLmqt3pWwRjR1tGIwkkZ2CvGJObYHsOuw3w==", 428 | "dev": true, 429 | "dependencies": { 430 | "buffer": "4.9.2", 431 | "events": "1.1.1", 432 | "ieee754": "1.1.13", 433 | "jmespath": "0.16.0", 434 | "querystring": "0.2.0", 435 | "sax": "1.2.1", 436 | "url": "0.10.3", 437 | "util": "^0.12.4", 438 | "uuid": "8.0.0", 439 | "xml2js": "0.5.0" 440 | }, 441 | "engines": { 442 | "node": ">= 10.0.0" 443 | } 444 | }, 445 | "node_modules/base64-js": { 446 | "version": "1.5.1", 447 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 448 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 449 | "dev": true, 450 | "funding": [ 451 | { 452 | "type": "github", 453 | "url": "https://github.com/sponsors/feross" 454 | }, 455 | { 456 | "type": "patreon", 457 | "url": "https://www.patreon.com/feross" 458 | }, 459 | { 460 | "type": "consulting", 461 | "url": "https://feross.org/support" 462 | } 463 | ] 464 | }, 465 | "node_modules/buffer": { 466 | "version": "4.9.2", 467 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 468 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 469 | "dev": true, 470 | "dependencies": { 471 | "base64-js": "^1.0.2", 472 | "ieee754": "^1.1.4", 473 | "isarray": "^1.0.0" 474 | } 475 | }, 476 | "node_modules/buffer-from": { 477 | "version": "1.1.1", 478 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 479 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 480 | }, 481 | "node_modules/call-bind": { 482 | "version": "1.0.2", 483 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 484 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 485 | "dev": true, 486 | "dependencies": { 487 | "function-bind": "^1.1.1", 488 | "get-intrinsic": "^1.0.2" 489 | }, 490 | "funding": { 491 | "url": "https://github.com/sponsors/ljharb" 492 | } 493 | }, 494 | "node_modules/constructs": { 495 | "version": "10.1.306", 496 | "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.1.306.tgz", 497 | "integrity": "sha512-7UruYLZLOk7qN9fQRX339iluZnqLVEPg8jSiKmKtehY4Sk0V91AOCe8/YccpYYTsMud3EKha8TT1zJa5SJPQug==", 498 | "engines": { 499 | "node": ">= 14.17.0" 500 | } 501 | }, 502 | "node_modules/events": { 503 | "version": "1.1.1", 504 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", 505 | "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", 506 | "dev": true, 507 | "engines": { 508 | "node": ">=0.4.x" 509 | } 510 | }, 511 | "node_modules/for-each": { 512 | "version": "0.3.3", 513 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 514 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 515 | "dev": true, 516 | "dependencies": { 517 | "is-callable": "^1.1.3" 518 | } 519 | }, 520 | "node_modules/fsevents": { 521 | "version": "2.3.2", 522 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 523 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 524 | "dev": true, 525 | "hasInstallScript": true, 526 | "optional": true, 527 | "os": [ 528 | "darwin" 529 | ], 530 | "engines": { 531 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 532 | } 533 | }, 534 | "node_modules/function-bind": { 535 | "version": "1.1.1", 536 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 537 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 538 | "dev": true 539 | }, 540 | "node_modules/get-intrinsic": { 541 | "version": "1.2.0", 542 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", 543 | "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", 544 | "dev": true, 545 | "dependencies": { 546 | "function-bind": "^1.1.1", 547 | "has": "^1.0.3", 548 | "has-symbols": "^1.0.3" 549 | }, 550 | "funding": { 551 | "url": "https://github.com/sponsors/ljharb" 552 | } 553 | }, 554 | "node_modules/gopd": { 555 | "version": "1.0.1", 556 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 557 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 558 | "dev": true, 559 | "dependencies": { 560 | "get-intrinsic": "^1.1.3" 561 | }, 562 | "funding": { 563 | "url": "https://github.com/sponsors/ljharb" 564 | } 565 | }, 566 | "node_modules/has": { 567 | "version": "1.0.3", 568 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 569 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 570 | "dev": true, 571 | "dependencies": { 572 | "function-bind": "^1.1.1" 573 | }, 574 | "engines": { 575 | "node": ">= 0.4.0" 576 | } 577 | }, 578 | "node_modules/has-symbols": { 579 | "version": "1.0.3", 580 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 581 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 582 | "dev": true, 583 | "engines": { 584 | "node": ">= 0.4" 585 | }, 586 | "funding": { 587 | "url": "https://github.com/sponsors/ljharb" 588 | } 589 | }, 590 | "node_modules/has-tostringtag": { 591 | "version": "1.0.0", 592 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 593 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 594 | "dev": true, 595 | "dependencies": { 596 | "has-symbols": "^1.0.2" 597 | }, 598 | "engines": { 599 | "node": ">= 0.4" 600 | }, 601 | "funding": { 602 | "url": "https://github.com/sponsors/ljharb" 603 | } 604 | }, 605 | "node_modules/husky": { 606 | "version": "6.0.0", 607 | "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", 608 | "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", 609 | "dev": true, 610 | "bin": { 611 | "husky": "lib/bin.js" 612 | }, 613 | "funding": { 614 | "url": "https://github.com/sponsors/typicode" 615 | } 616 | }, 617 | "node_modules/ieee754": { 618 | "version": "1.1.13", 619 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", 620 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", 621 | "dev": true 622 | }, 623 | "node_modules/inherits": { 624 | "version": "2.0.4", 625 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 626 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 627 | "dev": true 628 | }, 629 | "node_modules/is-arguments": { 630 | "version": "1.1.1", 631 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", 632 | "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", 633 | "dev": true, 634 | "dependencies": { 635 | "call-bind": "^1.0.2", 636 | "has-tostringtag": "^1.0.0" 637 | }, 638 | "engines": { 639 | "node": ">= 0.4" 640 | }, 641 | "funding": { 642 | "url": "https://github.com/sponsors/ljharb" 643 | } 644 | }, 645 | "node_modules/is-callable": { 646 | "version": "1.2.7", 647 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", 648 | "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", 649 | "dev": true, 650 | "engines": { 651 | "node": ">= 0.4" 652 | }, 653 | "funding": { 654 | "url": "https://github.com/sponsors/ljharb" 655 | } 656 | }, 657 | "node_modules/is-generator-function": { 658 | "version": "1.0.10", 659 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", 660 | "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", 661 | "dev": true, 662 | "dependencies": { 663 | "has-tostringtag": "^1.0.0" 664 | }, 665 | "engines": { 666 | "node": ">= 0.4" 667 | }, 668 | "funding": { 669 | "url": "https://github.com/sponsors/ljharb" 670 | } 671 | }, 672 | "node_modules/is-typed-array": { 673 | "version": "1.1.10", 674 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", 675 | "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", 676 | "dev": true, 677 | "dependencies": { 678 | "available-typed-arrays": "^1.0.5", 679 | "call-bind": "^1.0.2", 680 | "for-each": "^0.3.3", 681 | "gopd": "^1.0.1", 682 | "has-tostringtag": "^1.0.0" 683 | }, 684 | "engines": { 685 | "node": ">= 0.4" 686 | }, 687 | "funding": { 688 | "url": "https://github.com/sponsors/ljharb" 689 | } 690 | }, 691 | "node_modules/isarray": { 692 | "version": "1.0.0", 693 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 694 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", 695 | "dev": true 696 | }, 697 | "node_modules/jmespath": { 698 | "version": "0.16.0", 699 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", 700 | "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", 701 | "dev": true, 702 | "engines": { 703 | "node": ">= 0.6.0" 704 | } 705 | }, 706 | "node_modules/punycode": { 707 | "version": "1.3.2", 708 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 709 | "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", 710 | "dev": true 711 | }, 712 | "node_modules/querystring": { 713 | "version": "0.2.0", 714 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 715 | "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", 716 | "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", 717 | "dev": true, 718 | "engines": { 719 | "node": ">=0.4.x" 720 | } 721 | }, 722 | "node_modules/sax": { 723 | "version": "1.2.1", 724 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", 725 | "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", 726 | "dev": true 727 | }, 728 | "node_modules/source-map": { 729 | "version": "0.6.1", 730 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 731 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 732 | "engines": { 733 | "node": ">=0.10.0" 734 | } 735 | }, 736 | "node_modules/source-map-support": { 737 | "version": "0.5.19", 738 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 739 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 740 | "dependencies": { 741 | "buffer-from": "^1.0.0", 742 | "source-map": "^0.6.0" 743 | } 744 | }, 745 | "node_modules/tsort": { 746 | "version": "0.0.1", 747 | "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", 748 | "integrity": "sha1-4igPXoF/i/QnVlf9D5rr1E9aJ4Y=", 749 | "dev": true 750 | }, 751 | "node_modules/typescript": { 752 | "version": "4.9.5", 753 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", 754 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", 755 | "dev": true, 756 | "bin": { 757 | "tsc": "bin/tsc", 758 | "tsserver": "bin/tsserver" 759 | }, 760 | "engines": { 761 | "node": ">=4.2.0" 762 | } 763 | }, 764 | "node_modules/url": { 765 | "version": "0.10.3", 766 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", 767 | "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", 768 | "dev": true, 769 | "dependencies": { 770 | "punycode": "1.3.2", 771 | "querystring": "0.2.0" 772 | } 773 | }, 774 | "node_modules/util": { 775 | "version": "0.12.5", 776 | "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", 777 | "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", 778 | "dev": true, 779 | "dependencies": { 780 | "inherits": "^2.0.3", 781 | "is-arguments": "^1.0.4", 782 | "is-generator-function": "^1.0.7", 783 | "is-typed-array": "^1.1.3", 784 | "which-typed-array": "^1.1.2" 785 | } 786 | }, 787 | "node_modules/uuid": { 788 | "version": "8.0.0", 789 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", 790 | "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", 791 | "dev": true, 792 | "bin": { 793 | "uuid": "dist/bin/uuid" 794 | } 795 | }, 796 | "node_modules/which-typed-array": { 797 | "version": "1.1.9", 798 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", 799 | "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", 800 | "dev": true, 801 | "dependencies": { 802 | "available-typed-arrays": "^1.0.5", 803 | "call-bind": "^1.0.2", 804 | "for-each": "^0.3.3", 805 | "gopd": "^1.0.1", 806 | "has-tostringtag": "^1.0.0", 807 | "is-typed-array": "^1.1.10" 808 | }, 809 | "engines": { 810 | "node": ">= 0.4" 811 | }, 812 | "funding": { 813 | "url": "https://github.com/sponsors/ljharb" 814 | } 815 | }, 816 | "node_modules/xml2js": { 817 | "version": "0.5.0", 818 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", 819 | "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", 820 | "dev": true, 821 | "dependencies": { 822 | "sax": ">=0.6.0", 823 | "xmlbuilder": "~11.0.0" 824 | }, 825 | "engines": { 826 | "node": ">=4.0.0" 827 | } 828 | }, 829 | "node_modules/xmlbuilder": { 830 | "version": "11.0.1", 831 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", 832 | "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", 833 | "dev": true, 834 | "engines": { 835 | "node": ">=4.0" 836 | } 837 | } 838 | }, 839 | "dependencies": { 840 | "@aws-cdk/asset-awscli-v1": { 841 | "version": "2.2.135", 842 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.135.tgz", 843 | "integrity": "sha512-fdkrAjs/RQ9AmapA09cY5Gr9A+N+zYvUj0fuLYqeXjpl2BxLIpvkyfsL9IBxI/9lAUHHriLj6z84N6wZCgHscg==" 844 | }, 845 | "@aws-cdk/asset-kubectl-v20": { 846 | "version": "2.1.1", 847 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.1.tgz", 848 | "integrity": "sha512-U1ntiX8XiMRRRH5J1IdC+1t5CE89015cwyt5U63Cpk0GnMlN5+h9WsWMlKlPXZR4rdq/m806JRlBMRpBUB2Dhw==" 849 | }, 850 | "@aws-cdk/asset-node-proxy-agent-v5": { 851 | "version": "2.0.111", 852 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v5/-/asset-node-proxy-agent-v5-2.0.111.tgz", 853 | "integrity": "sha512-qfHTsN6E94gpAjc833KRoonZ+hN/n3IAvU5/LW1CLV0WGx56phThXo7rgUusOXI/Yna7K8FPgcmMDwSq0hD3WA==" 854 | }, 855 | "@types/node": { 856 | "version": "17.0.45", 857 | "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", 858 | "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", 859 | "dev": true 860 | }, 861 | "available-typed-arrays": { 862 | "version": "1.0.5", 863 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", 864 | "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", 865 | "dev": true 866 | }, 867 | "aws-cdk": { 868 | "version": "2.73.0", 869 | "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.73.0.tgz", 870 | "integrity": "sha512-4ZnY+OS83goCzv+1sCEpNTNiXWjY6KBzic2RNUObzpHjUskRSwUCtaeiv6OyZ55DZoP0tneAmWIBXHfixJ7iQw==", 871 | "dev": true, 872 | "requires": { 873 | "fsevents": "2.3.2" 874 | } 875 | }, 876 | "aws-cdk-lib": { 877 | "version": "2.73.0", 878 | "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.73.0.tgz", 879 | "integrity": "sha512-r9CUe3R7EThr9U0Eb7kQCK4Ee34TDeMH+bonvGD9rNRRTYDauvAgNCsx4DZYYksPrXLRzWjzVbuXAHaDDzWt+A==", 880 | "requires": { 881 | "@aws-cdk/asset-awscli-v1": "^2.2.97", 882 | "@aws-cdk/asset-kubectl-v20": "^2.1.1", 883 | "@aws-cdk/asset-node-proxy-agent-v5": "^2.0.77", 884 | "@balena/dockerignore": "^1.0.2", 885 | "case": "1.6.3", 886 | "fs-extra": "^9.1.0", 887 | "ignore": "^5.2.4", 888 | "jsonschema": "^1.4.1", 889 | "minimatch": "^3.1.2", 890 | "punycode": "^2.3.0", 891 | "semver": "^7.3.8", 892 | "table": "^6.8.1", 893 | "yaml": "1.10.2" 894 | }, 895 | "dependencies": { 896 | "@balena/dockerignore": { 897 | "version": "1.0.2", 898 | "bundled": true 899 | }, 900 | "ajv": { 901 | "version": "8.12.0", 902 | "bundled": true, 903 | "requires": { 904 | "fast-deep-equal": "^3.1.1", 905 | "json-schema-traverse": "^1.0.0", 906 | "require-from-string": "^2.0.2", 907 | "uri-js": "^4.2.2" 908 | } 909 | }, 910 | "ansi-regex": { 911 | "version": "5.0.1", 912 | "bundled": true 913 | }, 914 | "ansi-styles": { 915 | "version": "4.3.0", 916 | "bundled": true, 917 | "requires": { 918 | "color-convert": "^2.0.1" 919 | } 920 | }, 921 | "astral-regex": { 922 | "version": "2.0.0", 923 | "bundled": true 924 | }, 925 | "at-least-node": { 926 | "version": "1.0.0", 927 | "bundled": true 928 | }, 929 | "balanced-match": { 930 | "version": "1.0.2", 931 | "bundled": true 932 | }, 933 | "brace-expansion": { 934 | "version": "1.1.11", 935 | "bundled": true, 936 | "requires": { 937 | "balanced-match": "^1.0.0", 938 | "concat-map": "0.0.1" 939 | } 940 | }, 941 | "case": { 942 | "version": "1.6.3", 943 | "bundled": true 944 | }, 945 | "color-convert": { 946 | "version": "2.0.1", 947 | "bundled": true, 948 | "requires": { 949 | "color-name": "~1.1.4" 950 | } 951 | }, 952 | "color-name": { 953 | "version": "1.1.4", 954 | "bundled": true 955 | }, 956 | "concat-map": { 957 | "version": "0.0.1", 958 | "bundled": true 959 | }, 960 | "emoji-regex": { 961 | "version": "8.0.0", 962 | "bundled": true 963 | }, 964 | "fast-deep-equal": { 965 | "version": "3.1.3", 966 | "bundled": true 967 | }, 968 | "fs-extra": { 969 | "version": "9.1.0", 970 | "bundled": true, 971 | "requires": { 972 | "at-least-node": "^1.0.0", 973 | "graceful-fs": "^4.2.0", 974 | "jsonfile": "^6.0.1", 975 | "universalify": "^2.0.0" 976 | } 977 | }, 978 | "graceful-fs": { 979 | "version": "4.2.10", 980 | "bundled": true 981 | }, 982 | "ignore": { 983 | "version": "5.2.4", 984 | "bundled": true 985 | }, 986 | "is-fullwidth-code-point": { 987 | "version": "3.0.0", 988 | "bundled": true 989 | }, 990 | "json-schema-traverse": { 991 | "version": "1.0.0", 992 | "bundled": true 993 | }, 994 | "jsonfile": { 995 | "version": "6.1.0", 996 | "bundled": true, 997 | "requires": { 998 | "graceful-fs": "^4.1.6", 999 | "universalify": "^2.0.0" 1000 | } 1001 | }, 1002 | "jsonschema": { 1003 | "version": "1.4.1", 1004 | "bundled": true 1005 | }, 1006 | "lodash.truncate": { 1007 | "version": "4.4.2", 1008 | "bundled": true 1009 | }, 1010 | "lru-cache": { 1011 | "version": "6.0.0", 1012 | "bundled": true, 1013 | "requires": { 1014 | "yallist": "^4.0.0" 1015 | } 1016 | }, 1017 | "minimatch": { 1018 | "version": "3.1.2", 1019 | "bundled": true, 1020 | "requires": { 1021 | "brace-expansion": "^1.1.7" 1022 | } 1023 | }, 1024 | "punycode": { 1025 | "version": "2.3.0", 1026 | "bundled": true 1027 | }, 1028 | "require-from-string": { 1029 | "version": "2.0.2", 1030 | "bundled": true 1031 | }, 1032 | "semver": { 1033 | "version": "7.3.8", 1034 | "bundled": true, 1035 | "requires": { 1036 | "lru-cache": "^6.0.0" 1037 | } 1038 | }, 1039 | "slice-ansi": { 1040 | "version": "4.0.0", 1041 | "bundled": true, 1042 | "requires": { 1043 | "ansi-styles": "^4.0.0", 1044 | "astral-regex": "^2.0.0", 1045 | "is-fullwidth-code-point": "^3.0.0" 1046 | } 1047 | }, 1048 | "string-width": { 1049 | "version": "4.2.3", 1050 | "bundled": true, 1051 | "requires": { 1052 | "emoji-regex": "^8.0.0", 1053 | "is-fullwidth-code-point": "^3.0.0", 1054 | "strip-ansi": "^6.0.1" 1055 | } 1056 | }, 1057 | "strip-ansi": { 1058 | "version": "6.0.1", 1059 | "bundled": true, 1060 | "requires": { 1061 | "ansi-regex": "^5.0.1" 1062 | } 1063 | }, 1064 | "table": { 1065 | "version": "6.8.1", 1066 | "bundled": true, 1067 | "requires": { 1068 | "ajv": "^8.0.1", 1069 | "lodash.truncate": "^4.4.2", 1070 | "slice-ansi": "^4.0.0", 1071 | "string-width": "^4.2.3", 1072 | "strip-ansi": "^6.0.1" 1073 | } 1074 | }, 1075 | "universalify": { 1076 | "version": "2.0.0", 1077 | "bundled": true 1078 | }, 1079 | "uri-js": { 1080 | "version": "4.4.1", 1081 | "bundled": true, 1082 | "requires": { 1083 | "punycode": "^2.1.0" 1084 | } 1085 | }, 1086 | "yallist": { 1087 | "version": "4.0.0", 1088 | "bundled": true 1089 | }, 1090 | "yaml": { 1091 | "version": "1.10.2", 1092 | "bundled": true 1093 | } 1094 | } 1095 | }, 1096 | "aws-sdk": { 1097 | "version": "2.1354.0", 1098 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1354.0.tgz", 1099 | "integrity": "sha512-3aDxvyuOqMB9DqJguCq6p8momdsz0JR1axwkWOOCzHA7a35+Bw+WLmqt3pWwRjR1tGIwkkZ2CvGJObYHsOuw3w==", 1100 | "dev": true, 1101 | "requires": { 1102 | "buffer": "4.9.2", 1103 | "events": "1.1.1", 1104 | "ieee754": "1.1.13", 1105 | "jmespath": "0.16.0", 1106 | "querystring": "0.2.0", 1107 | "sax": "1.2.1", 1108 | "url": "0.10.3", 1109 | "util": "^0.12.4", 1110 | "uuid": "8.0.0", 1111 | "xml2js": "0.5.0" 1112 | } 1113 | }, 1114 | "base64-js": { 1115 | "version": "1.5.1", 1116 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 1117 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 1118 | "dev": true 1119 | }, 1120 | "buffer": { 1121 | "version": "4.9.2", 1122 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 1123 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 1124 | "dev": true, 1125 | "requires": { 1126 | "base64-js": "^1.0.2", 1127 | "ieee754": "^1.1.4", 1128 | "isarray": "^1.0.0" 1129 | } 1130 | }, 1131 | "buffer-from": { 1132 | "version": "1.1.1", 1133 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 1134 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 1135 | }, 1136 | "call-bind": { 1137 | "version": "1.0.2", 1138 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 1139 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 1140 | "dev": true, 1141 | "requires": { 1142 | "function-bind": "^1.1.1", 1143 | "get-intrinsic": "^1.0.2" 1144 | } 1145 | }, 1146 | "constructs": { 1147 | "version": "10.1.306", 1148 | "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.1.306.tgz", 1149 | "integrity": "sha512-7UruYLZLOk7qN9fQRX339iluZnqLVEPg8jSiKmKtehY4Sk0V91AOCe8/YccpYYTsMud3EKha8TT1zJa5SJPQug==" 1150 | }, 1151 | "events": { 1152 | "version": "1.1.1", 1153 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", 1154 | "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", 1155 | "dev": true 1156 | }, 1157 | "for-each": { 1158 | "version": "0.3.3", 1159 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 1160 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 1161 | "dev": true, 1162 | "requires": { 1163 | "is-callable": "^1.1.3" 1164 | } 1165 | }, 1166 | "fsevents": { 1167 | "version": "2.3.2", 1168 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1169 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1170 | "dev": true, 1171 | "optional": true 1172 | }, 1173 | "function-bind": { 1174 | "version": "1.1.1", 1175 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1176 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1177 | "dev": true 1178 | }, 1179 | "get-intrinsic": { 1180 | "version": "1.2.0", 1181 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", 1182 | "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", 1183 | "dev": true, 1184 | "requires": { 1185 | "function-bind": "^1.1.1", 1186 | "has": "^1.0.3", 1187 | "has-symbols": "^1.0.3" 1188 | } 1189 | }, 1190 | "gopd": { 1191 | "version": "1.0.1", 1192 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 1193 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 1194 | "dev": true, 1195 | "requires": { 1196 | "get-intrinsic": "^1.1.3" 1197 | } 1198 | }, 1199 | "has": { 1200 | "version": "1.0.3", 1201 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1202 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1203 | "dev": true, 1204 | "requires": { 1205 | "function-bind": "^1.1.1" 1206 | } 1207 | }, 1208 | "has-symbols": { 1209 | "version": "1.0.3", 1210 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1211 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 1212 | "dev": true 1213 | }, 1214 | "has-tostringtag": { 1215 | "version": "1.0.0", 1216 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 1217 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 1218 | "dev": true, 1219 | "requires": { 1220 | "has-symbols": "^1.0.2" 1221 | } 1222 | }, 1223 | "husky": { 1224 | "version": "6.0.0", 1225 | "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", 1226 | "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", 1227 | "dev": true 1228 | }, 1229 | "ieee754": { 1230 | "version": "1.1.13", 1231 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", 1232 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", 1233 | "dev": true 1234 | }, 1235 | "inherits": { 1236 | "version": "2.0.4", 1237 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1238 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1239 | "dev": true 1240 | }, 1241 | "is-arguments": { 1242 | "version": "1.1.1", 1243 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", 1244 | "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", 1245 | "dev": true, 1246 | "requires": { 1247 | "call-bind": "^1.0.2", 1248 | "has-tostringtag": "^1.0.0" 1249 | } 1250 | }, 1251 | "is-callable": { 1252 | "version": "1.2.7", 1253 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", 1254 | "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", 1255 | "dev": true 1256 | }, 1257 | "is-generator-function": { 1258 | "version": "1.0.10", 1259 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", 1260 | "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", 1261 | "dev": true, 1262 | "requires": { 1263 | "has-tostringtag": "^1.0.0" 1264 | } 1265 | }, 1266 | "is-typed-array": { 1267 | "version": "1.1.10", 1268 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", 1269 | "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", 1270 | "dev": true, 1271 | "requires": { 1272 | "available-typed-arrays": "^1.0.5", 1273 | "call-bind": "^1.0.2", 1274 | "for-each": "^0.3.3", 1275 | "gopd": "^1.0.1", 1276 | "has-tostringtag": "^1.0.0" 1277 | } 1278 | }, 1279 | "isarray": { 1280 | "version": "1.0.0", 1281 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1282 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", 1283 | "dev": true 1284 | }, 1285 | "jmespath": { 1286 | "version": "0.16.0", 1287 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", 1288 | "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", 1289 | "dev": true 1290 | }, 1291 | "punycode": { 1292 | "version": "1.3.2", 1293 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 1294 | "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", 1295 | "dev": true 1296 | }, 1297 | "querystring": { 1298 | "version": "0.2.0", 1299 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 1300 | "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", 1301 | "dev": true 1302 | }, 1303 | "sax": { 1304 | "version": "1.2.1", 1305 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", 1306 | "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", 1307 | "dev": true 1308 | }, 1309 | "source-map": { 1310 | "version": "0.6.1", 1311 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1312 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 1313 | }, 1314 | "source-map-support": { 1315 | "version": "0.5.19", 1316 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 1317 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 1318 | "requires": { 1319 | "buffer-from": "^1.0.0", 1320 | "source-map": "^0.6.0" 1321 | } 1322 | }, 1323 | "tsort": { 1324 | "version": "0.0.1", 1325 | "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", 1326 | "integrity": "sha1-4igPXoF/i/QnVlf9D5rr1E9aJ4Y=", 1327 | "dev": true 1328 | }, 1329 | "typescript": { 1330 | "version": "4.9.5", 1331 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", 1332 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", 1333 | "dev": true 1334 | }, 1335 | "url": { 1336 | "version": "0.10.3", 1337 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", 1338 | "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", 1339 | "dev": true, 1340 | "requires": { 1341 | "punycode": "1.3.2", 1342 | "querystring": "0.2.0" 1343 | } 1344 | }, 1345 | "util": { 1346 | "version": "0.12.5", 1347 | "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", 1348 | "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", 1349 | "dev": true, 1350 | "requires": { 1351 | "inherits": "^2.0.3", 1352 | "is-arguments": "^1.0.4", 1353 | "is-generator-function": "^1.0.7", 1354 | "is-typed-array": "^1.1.3", 1355 | "which-typed-array": "^1.1.2" 1356 | } 1357 | }, 1358 | "uuid": { 1359 | "version": "8.0.0", 1360 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", 1361 | "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", 1362 | "dev": true 1363 | }, 1364 | "which-typed-array": { 1365 | "version": "1.1.9", 1366 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", 1367 | "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", 1368 | "dev": true, 1369 | "requires": { 1370 | "available-typed-arrays": "^1.0.5", 1371 | "call-bind": "^1.0.2", 1372 | "for-each": "^0.3.3", 1373 | "gopd": "^1.0.1", 1374 | "has-tostringtag": "^1.0.0", 1375 | "is-typed-array": "^1.1.10" 1376 | } 1377 | }, 1378 | "xml2js": { 1379 | "version": "0.5.0", 1380 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", 1381 | "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", 1382 | "dev": true, 1383 | "requires": { 1384 | "sax": ">=0.6.0", 1385 | "xmlbuilder": "~11.0.0" 1386 | } 1387 | }, 1388 | "xmlbuilder": { 1389 | "version": "11.0.1", 1390 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", 1391 | "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", 1392 | "dev": true 1393 | } 1394 | } 1395 | } 1396 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cicd", 3 | "version": "0.2.0", 4 | "bin": { 5 | "cicd": "bin/cicd.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^17.0.40", 15 | "aws-cdk": "^2.27.0", 16 | "aws-sdk": "^2.1354.0", 17 | "husky": "^6.0.0", 18 | "tsort": "0.0.1", 19 | "typescript": "^4.7.3" 20 | }, 21 | "dependencies": { 22 | "aws-cdk-lib": "^2.27.0", 23 | "constructs": "^10.0.0", 24 | "source-map-support": "^0.5.19" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /project-config.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "naming": { 3 | "company": "acme", 4 | "dept": "markets", 5 | "project": "roadrunner" 6 | }, 7 | "deployment": { 8 | "region": "ca-central-1", 9 | "cicdRoleName": "deployment-role", 10 | "githubSecret": "github-token" 11 | }, 12 | "accountIds": { 13 | "cicd": "", 14 | "dev": "", 15 | "test": "", 16 | "prod": "" 17 | }, 18 | "sharedResources": { 19 | "cicdBucket": "cicd" 20 | }, 21 | "defaultRegions": { 22 | "cicd": "ca-central-1", 23 | "dev": "ca-central-1", 24 | "test": "ca-central-1", 25 | "prod": "ca-central-1" 26 | }, 27 | "seedPipeline": [ 28 | { 29 | "pipelineName": "simple-cicd", 30 | "repository": "aws-simple-cicd", 31 | "branch": "main", 32 | "type": "GitHub", 33 | "owner": "awslabs", 34 | "targets": ["cicd"] 35 | } 36 | ], 37 | "teamOne": [ 38 | { 39 | "pipelineName": "rocket-powered-skates", 40 | "ccRepoName": "rocket-powered-skates", 41 | "branch": "main", 42 | "type": "CodeCommit", 43 | "cron": "" 44 | }, 45 | { 46 | "pipelineName": "roadrunner-trap", 47 | "repository": "roadrunner-trap", 48 | "branch": "main", 49 | "type": "GitHub", 50 | "owner": "acme" 51 | }, 52 | { 53 | "pipelineName": "roadrunner-trap", 54 | "repository": "roadrunner-trap", 55 | "branch": "feature/ticket-1234", 56 | "type": "GitHub", 57 | "owner": "acme", 58 | "targets": ["dev", "test"] 59 | } 60 | ], 61 | "teamTwo": [ 62 | { 63 | "pipelineName": "bird-seed", 64 | "ccRepoName": "bird-seed", 65 | "branch": "feature/bug-1234", 66 | "type": "CodeCommit" 67 | } 68 | ] 69 | } -------------------------------------------------------------------------------- /scripts/assume-cross-account-role.env: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # SPDX-License-Identifier: MIT-0 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | # software and associated documentation files (the "Software"), to deal in the Software 7 | # without restriction, including without limitation the rights to use, copy, modify, 8 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | ### 18 | 19 | #!/bin/bash 20 | 21 | ROLE_NAME=role/${CROSS_ACCOUNT_ROLE} 22 | SESSION_NAME=${TARGET_ENV}-Deploy 23 | echo Assuming role ${ROLE_NAME} in account ${TARGET_ACCOUNT_ID} with session name ${SESSION_NAME} 24 | 25 | if [ -z "${TARGET_ACCOUNT_ID}" ]; then 26 | >&2 echo Error: TARGET_ACCOUNT_ID must be set. Assuming cross account role has failed! 27 | exit 1 28 | else 29 | IMPERSONATION=$(aws sts assume-role --role-arn "arn:aws:iam::${TARGET_ACCOUNT_ID}:${ROLE_NAME}" --role-session-name ${SESSION_NAME} --output text | tail -1) 30 | export AWS_ACCESS_KEY_ID=$(echo $IMPERSONATION | awk '{print $2}') 31 | export AWS_SECRET_ACCESS_KEY=$(echo $IMPERSONATION | awk '{print $4}') 32 | export AWS_SESSION_TOKEN=$(echo $IMPERSONATION | awk '{print $5}') 33 | fi 34 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "Nothing to build" -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | # Running CDK Project 8 | 9 | # Install CDK 10 | npm install -g aws-cdk 11 | 12 | # Install Dependencies 13 | npm install 14 | npm run build 15 | 16 | # Deploy 17 | cdk bootstrap 18 | cdk deploy --all --require-approval never 19 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "Nothing to test" -------------------------------------------------------------------------------- /simple-cicd.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "files.exclude": { 9 | "**/*.d.ts": true, 10 | "**/*.js": true, 11 | }, 12 | "java.configuration.updateBuildConfiguration": "automatic", 13 | "psi-header.config": { 14 | "forceToTop": true, 15 | "license": "MIT-0", 16 | "copyrightHolder": "Amazon.com, Inc. or its affiliates", 17 | }, 18 | "psi-header.changes-tracking": { 19 | "isActive": true, 20 | "modAuthor": "Modified By: ", 21 | "modDate": "Last Modified: ", 22 | "modDateFormat": "date", 23 | "include": [], 24 | "exclude": [ 25 | "markdown", 26 | "json", 27 | "jsonc", 28 | ], 29 | "excludeGlob": [ 30 | "cdk.out/**", 31 | "node_modules/**", 32 | "build/**", 33 | "**/.gitignore", 34 | "scripts/**", 35 | "**/*.drawio", 36 | "**/*.env", 37 | "**/*.tmpl" 38 | ], 39 | "autoHeader": "manualSave", 40 | "enforceHeader": true 41 | }, 42 | "psi-header.lang-config": [ 43 | { 44 | "language": "yaml", 45 | "begin": "###", 46 | "prefix": "# ", 47 | "end": "###", 48 | "blankLinesAfter": 2, 49 | }, 50 | { 51 | "language": "javascript", 52 | "begin": "/**", 53 | "prefix": " * ", 54 | "end": " */", 55 | "blankLinesAfter": 2, 56 | }, 57 | { 58 | "language": "typescript", 59 | "mapTo": "javascript" 60 | } 61 | ], 62 | "psi-header.variables": [ 63 | ["projectCreationYear", "2020"], 64 | ["spdxid","MIT-0"] 65 | ], 66 | "psi-header.templates": [ 67 | { 68 | "language": "*", 69 | "template": [ 70 | "Copyright <> Amazon.com, Inc. or its affiliates. All Rights Reserved.", 71 | "SPDX-License-Identifier: <>", 72 | "", 73 | "Permission is hereby granted, free of charge, to any person obtaining a copy of this", 74 | "software and associated documentation files (the \"Software\"), to deal in the Software", 75 | "without restriction, including without limitation the rights to use, copy, modify,", 76 | "merge, publish, distribute, sublicense, and/or sell copies of the Software, and to", 77 | "permit persons to whom the Software is furnished to do so.", 78 | "", 79 | "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,", 80 | "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", 81 | "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT", 82 | "HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", 83 | "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE", 84 | "SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." 85 | ] 86 | } 87 | ], 88 | } 89 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": ["es2018", ], 6 | "declaration": true, 7 | "resolveJsonModule": true, 8 | "esModuleInterop": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "noImplicitThis": true, 13 | "alwaysStrict": true, 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": false, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "typeRoots": ["./node_modules/@types"] 23 | }, 24 | "exclude": ["cdk.out"] 25 | } 26 | --------------------------------------------------------------------------------