├── .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 | 
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 | 
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 |
--------------------------------------------------------------------------------