diff --git a/packages/@aws-cdk/assets-docker/.jsii b/packages/@aws-cdk/assets-docker/.jsii new file mode 100644 index 0000000000000..5f85f94761ff8 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/.jsii @@ -0,0 +1,843 @@ +{ + "author": { + "name": "Amazon Web Services", + "organization": true, + "roles": [ + "author" + ], + "url": "https://aws.amazon.com" + }, + "dependencies": { + "@aws-cdk/assets": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.Assets", + "packageId": "Amazon.CDK.Assets", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cdk-assets", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.assets" + }, + "js": { + "npm": "@aws-cdk/assets" + }, + "python": { + "distName": "aws-cdk.assets", + "module": "aws_cdk.assets" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-cloudformation": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.CloudFormation", + "packageId": "Amazon.CDK.AWS.CloudFormation", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cloudformation", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.cloudformation" + }, + "js": { + "npm": "@aws-cdk/aws-cloudformation" + }, + "python": { + "distName": "aws-cdk.aws-cloudformation", + "module": "aws_cdk.aws_cloudformation" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-ecr": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.ECR", + "packageId": "Amazon.CDK.AWS.ECR", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "ecr", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.ecr" + }, + "js": { + "npm": "@aws-cdk/aws-ecr" + }, + "python": { + "distName": "aws-cdk.aws-ecr", + "module": "aws_cdk.aws_ecr" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-iam": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.IAM", + "packageId": "Amazon.CDK.AWS.IAM", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "iam", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.iam" + }, + "js": { + "npm": "@aws-cdk/aws-iam" + }, + "python": { + "distName": "aws-cdk.aws-iam", + "module": "aws_cdk.aws_iam" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-lambda": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.Lambda", + "packageId": "Amazon.CDK.AWS.Lambda", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "lambda", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.lambda" + }, + "js": { + "npm": "@aws-cdk/aws-lambda" + }, + "python": { + "distName": "aws-cdk.aws-lambda", + "module": "aws_cdk.aws_lambda" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-s3": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.S3", + "packageId": "Amazon.CDK.AWS.S3", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "s3", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.s3" + }, + "js": { + "npm": "@aws-cdk/aws-s3" + }, + "python": { + "distName": "aws-cdk.aws-s3", + "module": "aws_cdk.aws_s3" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/cdk": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK", + "packageId": "Amazon.CDK", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cdk", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk" + }, + "js": { + "npm": "@aws-cdk/cdk" + }, + "python": { + "distName": "aws-cdk.cdk", + "module": "aws_cdk.cdk" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/cx-api": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.CXAPI", + "packageId": "Amazon.CDK.CXAPI", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cdk-cx-api", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.cxapi" + }, + "js": { + "npm": "@aws-cdk/cx-api" + }, + "python": { + "distName": "aws-cdk.cx-api", + "module": "aws_cdk.cx_api" + } + }, + "version": "0.33.0" + } + }, + "dependencyClosure": { + "@aws-cdk/assets": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.Assets", + "packageId": "Amazon.CDK.Assets", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cdk-assets", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.assets" + }, + "js": { + "npm": "@aws-cdk/assets" + }, + "python": { + "distName": "aws-cdk.assets", + "module": "aws_cdk.assets" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-cloudformation": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.CloudFormation", + "packageId": "Amazon.CDK.AWS.CloudFormation", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cloudformation", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.cloudformation" + }, + "js": { + "npm": "@aws-cdk/aws-cloudformation" + }, + "python": { + "distName": "aws-cdk.aws-cloudformation", + "module": "aws_cdk.aws_cloudformation" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-cloudwatch": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.CloudWatch", + "packageId": "Amazon.CDK.AWS.CloudWatch", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cloudwatch", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.cloudwatch" + }, + "js": { + "npm": "@aws-cdk/aws-cloudwatch" + }, + "python": { + "distName": "aws-cdk.aws-cloudwatch", + "module": "aws_cdk.aws_cloudwatch" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-ec2": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.EC2", + "packageId": "Amazon.CDK.AWS.EC2", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "ec2", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.ec2" + }, + "js": { + "npm": "@aws-cdk/aws-ec2" + }, + "python": { + "distName": "aws-cdk.aws-ec2", + "module": "aws_cdk.aws_ec2" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-ecr": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.ECR", + "packageId": "Amazon.CDK.AWS.ECR", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "ecr", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.ecr" + }, + "js": { + "npm": "@aws-cdk/aws-ecr" + }, + "python": { + "distName": "aws-cdk.aws-ecr", + "module": "aws_cdk.aws_ecr" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-events": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.Events", + "packageId": "Amazon.CDK.AWS.Events", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "events", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.events" + }, + "js": { + "npm": "@aws-cdk/aws-events" + }, + "python": { + "distName": "aws-cdk.aws-events", + "module": "aws_cdk.aws_events" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-iam": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.IAM", + "packageId": "Amazon.CDK.AWS.IAM", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "iam", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.iam" + }, + "js": { + "npm": "@aws-cdk/aws-iam" + }, + "python": { + "distName": "aws-cdk.aws-iam", + "module": "aws_cdk.aws_iam" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-kms": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.KMS", + "packageId": "Amazon.CDK.AWS.KMS", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "kms", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.kms" + }, + "js": { + "npm": "@aws-cdk/aws-kms" + }, + "python": { + "distName": "aws-cdk.aws-kms", + "module": "aws_cdk.aws_kms" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-lambda": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.Lambda", + "packageId": "Amazon.CDK.AWS.Lambda", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "lambda", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.lambda" + }, + "js": { + "npm": "@aws-cdk/aws-lambda" + }, + "python": { + "distName": "aws-cdk.aws-lambda", + "module": "aws_cdk.aws_lambda" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-logs": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.Logs", + "packageId": "Amazon.CDK.AWS.Logs", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "logs", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.logs" + }, + "js": { + "npm": "@aws-cdk/aws-logs" + }, + "python": { + "distName": "aws-cdk.aws-logs", + "module": "aws_cdk.aws_logs" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-s3": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.S3", + "packageId": "Amazon.CDK.AWS.S3", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "s3", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.s3" + }, + "js": { + "npm": "@aws-cdk/aws-s3" + }, + "python": { + "distName": "aws-cdk.aws-s3", + "module": "aws_cdk.aws_s3" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-sns": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.SNS", + "packageId": "Amazon.CDK.AWS.SNS", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "sns", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.sns" + }, + "js": { + "npm": "@aws-cdk/aws-sns" + }, + "python": { + "distName": "aws-cdk.aws-sns", + "module": "aws_cdk.aws_sns" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/aws-sqs": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.AWS.SQS", + "packageId": "Amazon.CDK.AWS.SQS", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "sqs", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.services.sqs" + }, + "js": { + "npm": "@aws-cdk/aws-sqs" + }, + "python": { + "distName": "aws-cdk.aws-sqs", + "module": "aws_cdk.aws_sqs" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/cdk": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK", + "packageId": "Amazon.CDK", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cdk", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk" + }, + "js": { + "npm": "@aws-cdk/cdk" + }, + "python": { + "distName": "aws-cdk.cdk", + "module": "aws_cdk.cdk" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/cx-api": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.CXAPI", + "packageId": "Amazon.CDK.CXAPI", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cdk-cx-api", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.cxapi" + }, + "js": { + "npm": "@aws-cdk/cx-api" + }, + "python": { + "distName": "aws-cdk.cx-api", + "module": "aws_cdk.cx_api" + } + }, + "version": "0.33.0" + }, + "@aws-cdk/region-info": { + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.RegionInfo", + "packageId": "Amazon.CDK.RegionInfo", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cdk-region-info", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.regioninfo" + }, + "js": { + "npm": "@aws-cdk/region-info" + }, + "python": { + "distName": "aws-cdk.region-info", + "module": "aws_cdk.region_info" + } + }, + "version": "0.33.0" + } + }, + "description": "Docker image assets", + "docs": { + "stability": "experimental" + }, + "homepage": "https://github.com/awslabs/aws-cdk", + "jsiiVersion": "0.11.1 (build 09c4828)", + "license": "Apache-2.0", + "name": "@aws-cdk/assets-docker", + "readme": { + "markdown": "# AWS CDK Docker Image Assets\n\n\n---\n\n![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge)\n\n> This API is still under active development and subject to non-backward\n> compatible changes or removal in any future version. Use of the API is not recommended in production\n> environments. Experimental APIs are not subject to the Semantic Versioning model.\n\n---\n\n\nThis module allows bundling Docker images as assets.\n\nImages are built from a local Docker context directory (with a `Dockerfile`),\nuploaded to ECR by the CDK toolkit and/or your app's CI-CD pipeline, and can be\nnaturally referenced in your CDK app.\n\n```typescript\nimport { DockerImageAsset } from '@aws-cdk/assets-docker';\n\nconst asset = new DockerImageAsset(this, 'MyBuildImage', {\n directory: path.join(__dirname, 'my-image')\n});\n```\n\nThe directory `my-image` must include a `Dockerfile`.\n\nThis will instruct the toolkit to build a Docker image from `my-image`, push it\nto an AWS ECR repository and wire the name of the repository as CloudFormation\nparameters to your stack.\n\nUse `asset.imageUri` to reference the image (it includes both the ECR image URL\nand tag.\n\nYou can optionally pass build args to the `docker build` command by specifying\nthe `buildArgs` property:\n\n```typescript\nconst asset = new DockerImageAsset(this, 'MyBuildImage', {\n directory: path.join(__dirname, 'my-image'),\n buildArgs: {\n HTTP_PROXY: 'http://10.20.30.2:1234'\n }\n});\n```\n\n### Pull Permissions\n\nDepending on the consumer of your image asset, you will need to make sure\nthe principal has permissions to pull the image.\n\nIn most cases, you should use the `asset.repository.grantPull(principal)`\nmethod. This will modify the IAM policy of the principal to allow it to\npull images from this repository.\n\nIf the pulling principal is not in the same account or is an AWS service that\ndoesn't assume a role in your account (e.g. AWS CodeBuild), pull permissions\nmust be granted on the __resource policy__ (and not on the principal's policy).\nTo do that, you can use `asset.repository.addToResourcePolicy(statement)` to\ngrant the desired principal the following permissions: \"ecr:GetDownloadUrlForLayer\",\n\"ecr:BatchGetImage\" and \"ecr:BatchCheckLayerAvailability\".\n" + }, + "repository": { + "directory": "packages/@aws-cdk/assets-docker", + "type": "git", + "url": "https://github.com/awslabs/aws-cdk.git" + }, + "schema": "jsii/0.10.0", + "targets": { + "dotnet": { + "assemblyOriginatorKeyFile": "../../key.snk", + "namespace": "Amazon.CDK.Assets.Docker", + "packageId": "Amazon.CDK.Assets.Docker", + "signAssembly": true + }, + "java": { + "maven": { + "artifactId": "cdk-assets-docker", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.assets.docker" + }, + "js": { + "npm": "@aws-cdk/assets-docker" + }, + "python": { + "distName": "aws-cdk.assets-docker", + "module": "aws_cdk.assets_docker" + } + }, + "types": { + "@aws-cdk/assets-docker.DockerImageAsset": { + "assembly": "@aws-cdk/assets-docker", + "base": "@aws-cdk/cdk.Construct", + "docs": { + "remarks": "The image will be created in build time and uploaded to an ECR repository.", + "stability": "experimental", + "summary": "An asset that represents a Docker image." + }, + "fqn": "@aws-cdk/assets-docker.DockerImageAsset", + "initializer": { + "docs": { + "stability": "experimental" + }, + "parameters": [ + { + "name": "scope", + "type": { + "fqn": "@aws-cdk/cdk.Construct" + } + }, + { + "name": "id", + "type": { + "primitive": "string" + } + }, + { + "name": "props", + "type": { + "fqn": "@aws-cdk/assets-docker.DockerImageAssetProps" + } + } + ] + }, + "interfaces": [ + "@aws-cdk/assets.IAsset" + ], + "kind": "class", + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 39 + }, + "name": "DockerImageAsset", + "properties": [ + { + "docs": { + "remarks": "As this is\na late-bound token, it may not be used in construct IDs, but can be passed as a resource\nproperty in order to force a change on a resource when an asset is effectively updated. This is\nmore reliable than `sourceHash` in particular for assets which bundling phase involve external\nresources that can change over time (such as Docker image builds).", + "stability": "experimental", + "summary": "A hash of the bundle for of this asset, which is only available at deployment time." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 52 + }, + "name": "artifactHash", + "overrides": "@aws-cdk/assets.IAsset", + "type": { + "primitive": "string" + } + }, + { + "docs": { + "remarks": "As this is a plain\nstring, it can be used in construct IDs in order to enforce creation of a new resource when\nthe content hash has changed.", + "stability": "experimental", + "summary": "A hash of the source of this asset, which is available at construction time." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 51 + }, + "name": "sourceHash", + "overrides": "@aws-cdk/assets.IAsset", + "type": { + "primitive": "string" + } + }, + { + "docs": { + "remarks": "Use this reference to pull\nthe asset.", + "stability": "experimental", + "summary": "The full URI of the image (including a tag)." + }, + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 44 + }, + "name": "imageUri", + "type": { + "primitive": "string" + } + }, + { + "docs": { + "stability": "experimental", + "summary": "Repository where the image is stored." + }, + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 49 + }, + "name": "repository", + "type": { + "fqn": "@aws-cdk/aws-ecr.IRepository" + } + } + ] + }, + "@aws-cdk/assets-docker.DockerImageAssetProps": { + "assembly": "@aws-cdk/assets-docker", + "datatype": true, + "docs": { + "stability": "experimental" + }, + "fqn": "@aws-cdk/assets-docker.DockerImageAssetProps", + "interfaces": [ + "@aws-cdk/assets.CopyOptions" + ], + "kind": "interface", + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 9 + }, + "name": "DockerImageAssetProps", + "properties": [ + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "The directory where the Dockerfile is stored." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 13 + }, + "name": "directory", + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "no build args are passed", + "stability": "experimental", + "summary": "Build args to pass to the `docker build` command." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 31 + }, + "name": "buildArgs", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "map" + } + } + }, + { + "abstract": true, + "docs": { + "default": "automatically derived from the asset's ID.", + "remarks": "Specify this property if you need to statically address the image, e.g.\nfrom a Kubernetes Pod. Note, this is only the repository name, without the\nregistry and the tag parts.", + "stability": "experimental", + "summary": "ECR repository name." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/image-asset.ts", + "line": 24 + }, + "name": "repositoryName", + "optional": true, + "type": { + "primitive": "string" + } + } + ] + } + }, + "version": "0.33.0", + "fingerprint": "+ZrmcyQsOTTV1npBL41G5NTX6CiW/95mBvT0++AdlhY=" +} diff --git a/packages/@aws-cdk/assets-docker/lib/adopted-repository.d.ts b/packages/@aws-cdk/assets-docker/lib/adopted-repository.d.ts new file mode 100644 index 0000000000000..c7f997f05743c --- /dev/null +++ b/packages/@aws-cdk/assets-docker/lib/adopted-repository.d.ts @@ -0,0 +1,39 @@ +import ecr = require('@aws-cdk/aws-ecr'); +import iam = require('@aws-cdk/aws-iam'); +import cdk = require('@aws-cdk/cdk'); +interface AdoptedRepositoryProps { + /** + * An ECR repository to adopt. Once adopted, the repository will + * practically become part of this stack, so it will be removed when + * the stack is deleted. + */ + repositoryName: string; +} +/** + * An internal class used to adopt an ECR repository used for the locally built + * image into the stack. + * + * Since the repository is not created by the stack (but by the CDK toolkit), + * adopting will make the repository "owned" by the stack. It will be cleaned + * up when the stack gets deleted, to avoid leaving orphaned repositories on + * stack cleanup. + */ +export declare class AdoptedRepository extends ecr.RepositoryBase { + private readonly props; + readonly repositoryName: string; + readonly repositoryArn: string; + private readonly policyDocument; + constructor(scope: cdk.Construct, id: string, props: AdoptedRepositoryProps); + /** + * Export this repository from the stack + */ + export(): AdoptedRepositoryProps; + /** + * Adds a statement to the repository resource policy. + * + * Contrary to normal imported repositories, which no-op here, we can + * use the custom resource to modify the ECR resource policy if needed. + */ + addToResourcePolicy(statement: iam.PolicyStatement): void; +} +export {}; diff --git a/packages/@aws-cdk/assets-docker/lib/adopted-repository.js b/packages/@aws-cdk/assets-docker/lib/adopted-repository.js new file mode 100644 index 0000000000000..ecedf1f230a55 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/lib/adopted-repository.js @@ -0,0 +1,70 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const cfn = require("@aws-cdk/aws-cloudformation"); +const ecr = require("@aws-cdk/aws-ecr"); +const iam = require("@aws-cdk/aws-iam"); +const lambda = require("@aws-cdk/aws-lambda"); +const path = require("path"); +/** + * An internal class used to adopt an ECR repository used for the locally built + * image into the stack. + * + * Since the repository is not created by the stack (but by the CDK toolkit), + * adopting will make the repository "owned" by the stack. It will be cleaned + * up when the stack gets deleted, to avoid leaving orphaned repositories on + * stack cleanup. + */ +class AdoptedRepository extends ecr.RepositoryBase { + constructor(scope, id, props) { + super(scope, id); + this.props = props; + this.policyDocument = new iam.PolicyDocument(); + const fn = new lambda.SingletonFunction(this, 'Function', { + runtime: lambda.Runtime.NodeJS810, + lambdaPurpose: 'AdoptEcrRepository', + handler: 'handler.handler', + code: lambda.Code.asset(path.join(__dirname, 'adopt-repository')), + uuid: 'dbc60def-c595-44bc-aa5c-28c95d68f62c', + timeout: 300 + }); + fn.addToRolePolicy(new iam.PolicyStatement() + .addResource(ecr.Repository.arnForLocalRepository(props.repositoryName, this)) + .addActions('ecr:GetRepositoryPolicy', 'ecr:SetRepositoryPolicy', 'ecr:DeleteRepository', 'ecr:ListImages', 'ecr:BatchDeleteImage')); + const adopter = new cfn.CustomResource(this, 'Resource', { + resourceType: 'Custom::ECRAdoptedRepository', + provider: cfn.CustomResourceProvider.lambda(fn), + properties: { + RepositoryName: props.repositoryName, + PolicyDocument: this.policyDocument + } + }); + if (fn.role) { + // Need to explicitly depend on the role's policies, so they are applied before we try to use them + adopter.node.addDependency(fn.role); + } + // we use the Fn::GetAtt with the RepositoryName returned by the custom + // resource in order to implicitly create a dependency between consumers + // and the custom resource. + this.repositoryName = adopter.getAtt('RepositoryName').toString(); + // this this repository is "local" to the stack (in the same region/account) + // we can render it's ARN from it's name. + this.repositoryArn = ecr.Repository.arnForLocalRepository(this.repositoryName, this); + } + /** + * Export this repository from the stack + */ + export() { + return this.props; + } + /** + * Adds a statement to the repository resource policy. + * + * Contrary to normal imported repositories, which no-op here, we can + * use the custom resource to modify the ECR resource policy if needed. + */ + addToResourcePolicy(statement) { + this.policyDocument.addStatement(statement); + } +} +exports.AdoptedRepository = AdoptedRepository; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRvcHRlZC1yZXBvc2l0b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYWRvcHRlZC1yZXBvc2l0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbURBQW9EO0FBQ3BELHdDQUF5QztBQUN6Qyx3Q0FBeUM7QUFDekMsOENBQStDO0FBRS9DLDZCQUE4QjtBQVc5Qjs7Ozs7Ozs7R0FRRztBQUNILE1BQWEsaUJBQWtCLFNBQVEsR0FBRyxDQUFDLGNBQWM7SUFNdkQsWUFBWSxLQUFvQixFQUFFLEVBQVUsRUFBbUIsS0FBNkI7UUFDMUYsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUQ0QyxVQUFLLEdBQUwsS0FBSyxDQUF3QjtRQUYzRSxtQkFBYyxHQUFHLElBQUksR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBS3pELE1BQU0sRUFBRSxHQUFHLElBQUksTUFBTSxDQUFDLGlCQUFpQixDQUFDLElBQUksRUFBRSxVQUFVLEVBQUU7WUFDeEQsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUztZQUNqQyxhQUFhLEVBQUUsb0JBQW9CO1lBQ25DLE9BQU8sRUFBRSxpQkFBaUI7WUFDMUIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGtCQUFrQixDQUFDLENBQUM7WUFDakUsSUFBSSxFQUFFLHNDQUFzQztZQUM1QyxPQUFPLEVBQUUsR0FBRztTQUNiLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxlQUFlLENBQUMsSUFBSSxHQUFHLENBQUMsZUFBZSxFQUFFO2FBQ3pDLFdBQVcsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxjQUFjLEVBQUUsSUFBSSxDQUFDLENBQUM7YUFDN0UsVUFBVSxDQUNULHlCQUF5QixFQUN6Qix5QkFBeUIsRUFDekIsc0JBQXNCLEVBQ3RCLGdCQUFnQixFQUNoQixzQkFBc0IsQ0FDdkIsQ0FBQyxDQUFDO1FBRUwsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxVQUFVLEVBQUU7WUFDdkQsWUFBWSxFQUFFLDhCQUE4QjtZQUM1QyxRQUFRLEVBQUUsR0FBRyxDQUFDLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDL0MsVUFBVSxFQUFFO2dCQUNWLGNBQWMsRUFBRSxLQUFLLENBQUMsY0FBYztnQkFDcEMsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjO2FBQ3BDO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFO1lBQ1gsa0dBQWtHO1lBQ2xHLE9BQU8sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNyQztRQUVELHVFQUF1RTtRQUN2RSx3RUFBd0U7UUFDeEUsMkJBQTJCO1FBQzNCLElBQUksQ0FBQyxjQUFjLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBRWxFLDRFQUE0RTtRQUM1RSx5Q0FBeUM7UUFDekMsSUFBSSxDQUFDLGFBQWEsR0FBRyxHQUFHLENBQUMsVUFBVSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdkYsQ0FBQztJQUVEOztPQUVHO0lBQ0ksTUFBTTtRQUNYLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQztJQUNwQixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxtQkFBbUIsQ0FBQyxTQUE4QjtRQUN2RCxJQUFJLENBQUMsY0FBYyxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUM5QyxDQUFDO0NBQ0Y7QUFuRUQsOENBbUVDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNmbiA9IHJlcXVpcmUoJ0Bhd3MtY2RrL2F3cy1jbG91ZGZvcm1hdGlvbicpO1xuaW1wb3J0IGVjciA9IHJlcXVpcmUoJ0Bhd3MtY2RrL2F3cy1lY3InKTtcbmltcG9ydCBpYW0gPSByZXF1aXJlKCdAYXdzLWNkay9hd3MtaWFtJyk7XG5pbXBvcnQgbGFtYmRhID0gcmVxdWlyZSgnQGF3cy1jZGsvYXdzLWxhbWJkYScpO1xuaW1wb3J0IGNkayA9IHJlcXVpcmUoJ0Bhd3MtY2RrL2NkaycpO1xuaW1wb3J0IHBhdGggPSByZXF1aXJlKCdwYXRoJyk7XG5cbmludGVyZmFjZSBBZG9wdGVkUmVwb3NpdG9yeVByb3BzIHtcbiAgLyoqXG4gICAqIEFuIEVDUiByZXBvc2l0b3J5IHRvIGFkb3B0LiBPbmNlIGFkb3B0ZWQsIHRoZSByZXBvc2l0b3J5IHdpbGxcbiAgICogcHJhY3RpY2FsbHkgYmVjb21lIHBhcnQgb2YgdGhpcyBzdGFjaywgc28gaXQgd2lsbCBiZSByZW1vdmVkIHdoZW5cbiAgICogdGhlIHN0YWNrIGlzIGRlbGV0ZWQuXG4gICAqL1xuICByZXBvc2l0b3J5TmFtZTogc3RyaW5nO1xufVxuXG4vKipcbiAqIEFuIGludGVybmFsIGNsYXNzIHVzZWQgdG8gYWRvcHQgYW4gRUNSIHJlcG9zaXRvcnkgdXNlZCBmb3IgdGhlIGxvY2FsbHkgYnVpbHRcbiAqIGltYWdlIGludG8gdGhlIHN0YWNrLlxuICpcbiAqIFNpbmNlIHRoZSByZXBvc2l0b3J5IGlzIG5vdCBjcmVhdGVkIGJ5IHRoZSBzdGFjayAoYnV0IGJ5IHRoZSBDREsgdG9vbGtpdCksXG4gKiBhZG9wdGluZyB3aWxsIG1ha2UgdGhlIHJlcG9zaXRvcnkgXCJvd25lZFwiIGJ5IHRoZSBzdGFjay4gSXQgd2lsbCBiZSBjbGVhbmVkXG4gKiB1cCB3aGVuIHRoZSBzdGFjayBnZXRzIGRlbGV0ZWQsIHRvIGF2b2lkIGxlYXZpbmcgb3JwaGFuZWQgcmVwb3NpdG9yaWVzIG9uXG4gKiBzdGFjayBjbGVhbnVwLlxuICovXG5leHBvcnQgY2xhc3MgQWRvcHRlZFJlcG9zaXRvcnkgZXh0ZW5kcyBlY3IuUmVwb3NpdG9yeUJhc2Uge1xuICBwdWJsaWMgcmVhZG9ubHkgcmVwb3NpdG9yeU5hbWU6IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IHJlcG9zaXRvcnlBcm46IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IHBvbGljeURvY3VtZW50ID0gbmV3IGlhbS5Qb2xpY3lEb2N1bWVudCgpO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBjZGsuQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcml2YXRlIHJlYWRvbmx5IHByb3BzOiBBZG9wdGVkUmVwb3NpdG9yeVByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGNvbnN0IGZuID0gbmV3IGxhbWJkYS5TaW5nbGV0b25GdW5jdGlvbih0aGlzLCAnRnVuY3Rpb24nLCB7XG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5Ob2RlSlM4MTAsXG4gICAgICBsYW1iZGFQdXJwb3NlOiAnQWRvcHRFY3JSZXBvc2l0b3J5JyxcbiAgICAgIGhhbmRsZXI6ICdoYW5kbGVyLmhhbmRsZXInLFxuICAgICAgY29kZTogbGFtYmRhLkNvZGUuYXNzZXQocGF0aC5qb2luKF9fZGlybmFtZSwgJ2Fkb3B0LXJlcG9zaXRvcnknKSksXG4gICAgICB1dWlkOiAnZGJjNjBkZWYtYzU5NS00NGJjLWFhNWMtMjhjOTVkNjhmNjJjJyxcbiAgICAgIHRpbWVvdXQ6IDMwMFxuICAgIH0pO1xuXG4gICAgZm4uYWRkVG9Sb2xlUG9saWN5KG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KClcbiAgICAgIC5hZGRSZXNvdXJjZShlY3IuUmVwb3NpdG9yeS5hcm5Gb3JMb2NhbFJlcG9zaXRvcnkocHJvcHMucmVwb3NpdG9yeU5hbWUsIHRoaXMpKVxuICAgICAgLmFkZEFjdGlvbnMoXG4gICAgICAgICdlY3I6R2V0UmVwb3NpdG9yeVBvbGljeScsXG4gICAgICAgICdlY3I6U2V0UmVwb3NpdG9yeVBvbGljeScsXG4gICAgICAgICdlY3I6RGVsZXRlUmVwb3NpdG9yeScsXG4gICAgICAgICdlY3I6TGlzdEltYWdlcycsXG4gICAgICAgICdlY3I6QmF0Y2hEZWxldGVJbWFnZSdcbiAgICAgICkpO1xuXG4gICAgY29uc3QgYWRvcHRlciA9IG5ldyBjZm4uQ3VzdG9tUmVzb3VyY2UodGhpcywgJ1Jlc291cmNlJywge1xuICAgICAgcmVzb3VyY2VUeXBlOiAnQ3VzdG9tOjpFQ1JBZG9wdGVkUmVwb3NpdG9yeScsXG4gICAgICBwcm92aWRlcjogY2ZuLkN1c3RvbVJlc291cmNlUHJvdmlkZXIubGFtYmRhKGZuKSxcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgUmVwb3NpdG9yeU5hbWU6IHByb3BzLnJlcG9zaXRvcnlOYW1lLFxuICAgICAgICBQb2xpY3lEb2N1bWVudDogdGhpcy5wb2xpY3lEb2N1bWVudFxuICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChmbi5yb2xlKSB7XG4gICAgICAvLyBOZWVkIHRvIGV4cGxpY2l0bHkgZGVwZW5kIG9uIHRoZSByb2xlJ3MgcG9saWNpZXMsIHNvIHRoZXkgYXJlIGFwcGxpZWQgYmVmb3JlIHdlIHRyeSB0byB1c2UgdGhlbVxuICAgICAgYWRvcHRlci5ub2RlLmFkZERlcGVuZGVuY3koZm4ucm9sZSk7XG4gICAgfVxuXG4gICAgLy8gd2UgdXNlIHRoZSBGbjo6R2V0QXR0IHdpdGggdGhlIFJlcG9zaXRvcnlOYW1lIHJldHVybmVkIGJ5IHRoZSBjdXN0b21cbiAgICAvLyByZXNvdXJjZSBpbiBvcmRlciB0byBpbXBsaWNpdGx5IGNyZWF0ZSBhIGRlcGVuZGVuY3kgYmV0d2VlbiBjb25zdW1lcnNcbiAgICAvLyBhbmQgdGhlIGN1c3RvbSByZXNvdXJjZS5cbiAgICB0aGlzLnJlcG9zaXRvcnlOYW1lID0gYWRvcHRlci5nZXRBdHQoJ1JlcG9zaXRvcnlOYW1lJykudG9TdHJpbmcoKTtcblxuICAgIC8vIHRoaXMgdGhpcyByZXBvc2l0b3J5IGlzIFwibG9jYWxcIiB0byB0aGUgc3RhY2sgKGluIHRoZSBzYW1lIHJlZ2lvbi9hY2NvdW50KVxuICAgIC8vIHdlIGNhbiByZW5kZXIgaXQncyBBUk4gZnJvbSBpdCdzIG5hbWUuXG4gICAgdGhpcy5yZXBvc2l0b3J5QXJuID0gZWNyLlJlcG9zaXRvcnkuYXJuRm9yTG9jYWxSZXBvc2l0b3J5KHRoaXMucmVwb3NpdG9yeU5hbWUsIHRoaXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cG9ydCB0aGlzIHJlcG9zaXRvcnkgZnJvbSB0aGUgc3RhY2tcbiAgICovXG4gIHB1YmxpYyBleHBvcnQoKSB7XG4gICAgcmV0dXJuIHRoaXMucHJvcHM7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHN0YXRlbWVudCB0byB0aGUgcmVwb3NpdG9yeSByZXNvdXJjZSBwb2xpY3kuXG4gICAqXG4gICAqIENvbnRyYXJ5IHRvIG5vcm1hbCBpbXBvcnRlZCByZXBvc2l0b3JpZXMsIHdoaWNoIG5vLW9wIGhlcmUsIHdlIGNhblxuICAgKiB1c2UgdGhlIGN1c3RvbSByZXNvdXJjZSB0byBtb2RpZnkgdGhlIEVDUiByZXNvdXJjZSBwb2xpY3kgaWYgbmVlZGVkLlxuICAgKi9cbiAgcHVibGljIGFkZFRvUmVzb3VyY2VQb2xpY3koc3RhdGVtZW50OiBpYW0uUG9saWN5U3RhdGVtZW50KSB7XG4gICAgdGhpcy5wb2xpY3lEb2N1bWVudC5hZGRTdGF0ZW1lbnQoc3RhdGVtZW50KTtcbiAgfVxufVxuIl19 \ No newline at end of file diff --git a/packages/@aws-cdk/assets-docker/lib/image-asset.d.ts b/packages/@aws-cdk/assets-docker/lib/image-asset.d.ts new file mode 100644 index 0000000000000..635b26ea59550 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/lib/image-asset.d.ts @@ -0,0 +1,50 @@ +import assets = require('@aws-cdk/assets'); +import ecr = require('@aws-cdk/aws-ecr'); +import cdk = require('@aws-cdk/cdk'); +export interface DockerImageAssetProps extends assets.CopyOptions { + /** + * The directory where the Dockerfile is stored + */ + readonly directory: string; + /** + * ECR repository name + * + * Specify this property if you need to statically address the image, e.g. + * from a Kubernetes Pod. Note, this is only the repository name, without the + * registry and the tag parts. + * + * @default automatically derived from the asset's ID. + */ + readonly repositoryName?: string; + /** + * Build args to pass to the `docker build` command + * + * @default no build args are passed + */ + readonly buildArgs?: { + [key: string]: string; + }; +} +/** + * An asset that represents a Docker image. + * + * The image will be created in build time and uploaded to an ECR repository. + */ +export declare class DockerImageAsset extends cdk.Construct implements assets.IAsset { + /** + * The full URI of the image (including a tag). Use this reference to pull + * the asset. + */ + imageUri: string; + /** + * Repository where the image is stored + */ + repository: ecr.IRepository; + readonly sourceHash: string; + readonly artifactHash: string; + /** + * Directory where the source files are stored + */ + private readonly directory; + constructor(scope: cdk.Construct, id: string, props: DockerImageAssetProps); +} diff --git a/packages/@aws-cdk/assets-docker/lib/image-asset.js b/packages/@aws-cdk/assets-docker/lib/image-asset.js new file mode 100644 index 0000000000000..55f2f17e2de07 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/lib/image-asset.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const assets = require("@aws-cdk/assets"); +const cdk = require("@aws-cdk/cdk"); +const cxapi = require("@aws-cdk/cx-api"); +const fs = require("fs"); +const path = require("path"); +const adopted_repository_1 = require("./adopted-repository"); +/** + * An asset that represents a Docker image. + * + * The image will be created in build time and uploaded to an ECR repository. + */ +class DockerImageAsset extends cdk.Construct { + constructor(scope, id, props) { + super(scope, id); + // resolve full path + const dir = path.resolve(props.directory); + if (!fs.existsSync(dir)) { + throw new Error(`Cannot find image directory at ${dir}`); + } + if (!fs.existsSync(path.join(dir, 'Dockerfile'))) { + throw new Error(`No 'Dockerfile' found in ${dir}`); + } + const staging = new assets.Staging(this, 'Staging', { + ...props, + sourcePath: dir + }); + this.directory = staging.stagedPath; + this.sourceHash = staging.sourceHash; + const imageNameParameter = new cdk.CfnParameter(this, 'ImageName', { + type: 'String', + description: `ECR repository name and tag asset "${this.node.path}"`, + }); + const asset = { + id: this.node.uniqueId, + packaging: 'container-image', + path: this.directory, + sourceHash: this.sourceHash, + imageNameParameter: imageNameParameter.logicalId, + repositoryName: props.repositoryName, + buildArgs: props.buildArgs + }; + this.node.addMetadata(cxapi.ASSET_METADATA, asset); + // Parse repository name and tag from the parameter (@sha256:) + // Example: cdk/cdkexampleimageb2d7f504@sha256:72c4f956379a43b5623d529ddd969f6826dde944d6221f445ff3e7add9875500 + const components = cdk.Fn.split('@sha256:', imageNameParameter.stringValue); + const repositoryName = cdk.Fn.select(0, components).toString(); + const imageSha = cdk.Fn.select(1, components).toString(); + // Require that repository adoption happens first, so we route the + // input ARN into the Custom Resource and then get the URI which we use to + // refer to the image FROM the Custom Resource. + // + // If adoption fails (because the repository might be twice-adopted), we + // haven't already started using the image. + this.repository = new adopted_repository_1.AdoptedRepository(this, 'AdoptRepository', { repositoryName }); + this.imageUri = `${this.repository.repositoryUri}@sha256:${imageSha}`; + this.artifactHash = imageSha; + } +} +exports.DockerImageAsset = DockerImageAsset; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtYXNzZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbWFnZS1hc3NldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDBDQUEyQztBQUUzQyxvQ0FBcUM7QUFDckMseUNBQTBDO0FBQzFDLHlCQUEwQjtBQUMxQiw2QkFBOEI7QUFDOUIsNkRBQXlEO0FBMkJ6RDs7OztHQUlHO0FBQ0gsTUFBYSxnQkFBaUIsU0FBUSxHQUFHLENBQUMsU0FBUztJQW9CakQsWUFBWSxLQUFvQixFQUFFLEVBQVUsRUFBRSxLQUE0QjtRQUN4RSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLG9CQUFvQjtRQUNwQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQyxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1NBQzFEO1FBQ0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsWUFBWSxDQUFDLENBQUMsRUFBRTtZQUNoRCxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixHQUFHLEVBQUUsQ0FBQyxDQUFDO1NBQ3BEO1FBRUQsTUFBTSxPQUFPLEdBQUcsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxTQUFTLEVBQUU7WUFDbEQsR0FBRyxLQUFLO1lBQ1IsVUFBVSxFQUFFLEdBQUc7U0FDaEIsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDO1FBQ3BDLElBQUksQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQztRQUVyQyxNQUFNLGtCQUFrQixHQUFHLElBQUksR0FBRyxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFO1lBQ2pFLElBQUksRUFBRSxRQUFRO1lBQ2QsV0FBVyxFQUFFLHNDQUFzQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRztTQUNyRSxDQUFDLENBQUM7UUFFSCxNQUFNLEtBQUssR0FBMkM7WUFDcEQsRUFBRSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUTtZQUN0QixTQUFTLEVBQUUsaUJBQWlCO1lBQzVCLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUztZQUNwQixVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVU7WUFDM0Isa0JBQWtCLEVBQUUsa0JBQWtCLENBQUMsU0FBUztZQUNoRCxjQUFjLEVBQUUsS0FBSyxDQUFDLGNBQWM7WUFDcEMsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1NBQzNCLENBQUM7UUFFRixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsY0FBYyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRW5ELDhFQUE4RTtRQUM5RSwrR0FBK0c7UUFDL0csTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLGtCQUFrQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzVFLE1BQU0sY0FBYyxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUMvRCxNQUFNLFFBQVEsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFekQsa0VBQWtFO1FBQ2xFLDBFQUEwRTtRQUMxRSwrQ0FBK0M7UUFDL0MsRUFBRTtRQUNGLHdFQUF3RTtRQUN4RSwyQ0FBMkM7UUFDM0MsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLHNDQUFpQixDQUFDLElBQUksRUFBRSxpQkFBaUIsRUFBRSxFQUFFLGNBQWMsRUFBRSxDQUFDLENBQUM7UUFDckYsSUFBSSxDQUFDLFFBQVEsR0FBRyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxXQUFXLFFBQVEsRUFBRSxDQUFDO1FBQ3RFLElBQUksQ0FBQyxZQUFZLEdBQUcsUUFBUSxDQUFDO0lBQy9CLENBQUM7Q0FDRjtBQXpFRCw0Q0F5RUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXRzID0gcmVxdWlyZSgnQGF3cy1jZGsvYXNzZXRzJyk7XG5pbXBvcnQgZWNyID0gcmVxdWlyZSgnQGF3cy1jZGsvYXdzLWVjcicpO1xuaW1wb3J0IGNkayA9IHJlcXVpcmUoJ0Bhd3MtY2RrL2NkaycpO1xuaW1wb3J0IGN4YXBpID0gcmVxdWlyZSgnQGF3cy1jZGsvY3gtYXBpJyk7XG5pbXBvcnQgZnMgPSByZXF1aXJlKCdmcycpO1xuaW1wb3J0IHBhdGggPSByZXF1aXJlKCdwYXRoJyk7XG5pbXBvcnQgeyBBZG9wdGVkUmVwb3NpdG9yeSB9IGZyb20gJy4vYWRvcHRlZC1yZXBvc2l0b3J5JztcblxuZXhwb3J0IGludGVyZmFjZSBEb2NrZXJJbWFnZUFzc2V0UHJvcHMgZXh0ZW5kcyBhc3NldHMuQ29weU9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGRpcmVjdG9yeSB3aGVyZSB0aGUgRG9ja2VyZmlsZSBpcyBzdG9yZWRcbiAgICovXG4gIHJlYWRvbmx5IGRpcmVjdG9yeTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBFQ1IgcmVwb3NpdG9yeSBuYW1lXG4gICAqXG4gICAqIFNwZWNpZnkgdGhpcyBwcm9wZXJ0eSBpZiB5b3UgbmVlZCB0byBzdGF0aWNhbGx5IGFkZHJlc3MgdGhlIGltYWdlLCBlLmcuXG4gICAqIGZyb20gYSBLdWJlcm5ldGVzIFBvZC4gTm90ZSwgdGhpcyBpcyBvbmx5IHRoZSByZXBvc2l0b3J5IG5hbWUsIHdpdGhvdXQgdGhlXG4gICAqIHJlZ2lzdHJ5IGFuZCB0aGUgdGFnIHBhcnRzLlxuICAgKlxuICAgKiBAZGVmYXVsdCBhdXRvbWF0aWNhbGx5IGRlcml2ZWQgZnJvbSB0aGUgYXNzZXQncyBJRC5cbiAgICovXG4gIHJlYWRvbmx5IHJlcG9zaXRvcnlOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBCdWlsZCBhcmdzIHRvIHBhc3MgdG8gdGhlIGBkb2NrZXIgYnVpbGRgIGNvbW1hbmRcbiAgICpcbiAgICogQGRlZmF1bHQgbm8gYnVpbGQgYXJncyBhcmUgcGFzc2VkXG4gICAqL1xuICByZWFkb25seSBidWlsZEFyZ3M/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9O1xufVxuXG4vKipcbiAqIEFuIGFzc2V0IHRoYXQgcmVwcmVzZW50cyBhIERvY2tlciBpbWFnZS5cbiAqXG4gKiBUaGUgaW1hZ2Ugd2lsbCBiZSBjcmVhdGVkIGluIGJ1aWxkIHRpbWUgYW5kIHVwbG9hZGVkIHRvIGFuIEVDUiByZXBvc2l0b3J5LlxuICovXG5leHBvcnQgY2xhc3MgRG9ja2VySW1hZ2VBc3NldCBleHRlbmRzIGNkay5Db25zdHJ1Y3QgaW1wbGVtZW50cyBhc3NldHMuSUFzc2V0IHtcbiAgLyoqXG4gICAqIFRoZSBmdWxsIFVSSSBvZiB0aGUgaW1hZ2UgKGluY2x1ZGluZyBhIHRhZykuIFVzZSB0aGlzIHJlZmVyZW5jZSB0byBwdWxsXG4gICAqIHRoZSBhc3NldC5cbiAgICovXG4gIHB1YmxpYyBpbWFnZVVyaTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSZXBvc2l0b3J5IHdoZXJlIHRoZSBpbWFnZSBpcyBzdG9yZWRcbiAgICovXG4gIHB1YmxpYyByZXBvc2l0b3J5OiBlY3IuSVJlcG9zaXRvcnk7XG5cbiAgcHVibGljIHJlYWRvbmx5IHNvdXJjZUhhc2g6IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IGFydGlmYWN0SGFzaDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBEaXJlY3Rvcnkgd2hlcmUgdGhlIHNvdXJjZSBmaWxlcyBhcmUgc3RvcmVkXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGRpcmVjdG9yeTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBjZGsuQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogRG9ja2VySW1hZ2VBc3NldFByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIC8vIHJlc29sdmUgZnVsbCBwYXRoXG4gICAgY29uc3QgZGlyID0gcGF0aC5yZXNvbHZlKHByb3BzLmRpcmVjdG9yeSk7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKGRpcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGZpbmQgaW1hZ2UgZGlyZWN0b3J5IGF0ICR7ZGlyfWApO1xuICAgIH1cbiAgICBpZiAoIWZzLmV4aXN0c1N5bmMocGF0aC5qb2luKGRpciwgJ0RvY2tlcmZpbGUnKSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gJ0RvY2tlcmZpbGUnIGZvdW5kIGluICR7ZGlyfWApO1xuICAgIH1cblxuICAgIGNvbnN0IHN0YWdpbmcgPSBuZXcgYXNzZXRzLlN0YWdpbmcodGhpcywgJ1N0YWdpbmcnLCB7XG4gICAgICAuLi5wcm9wcyxcbiAgICAgIHNvdXJjZVBhdGg6IGRpclxuICAgIH0pO1xuXG4gICAgdGhpcy5kaXJlY3RvcnkgPSBzdGFnaW5nLnN0YWdlZFBhdGg7XG4gICAgdGhpcy5zb3VyY2VIYXNoID0gc3RhZ2luZy5zb3VyY2VIYXNoO1xuXG4gICAgY29uc3QgaW1hZ2VOYW1lUGFyYW1ldGVyID0gbmV3IGNkay5DZm5QYXJhbWV0ZXIodGhpcywgJ0ltYWdlTmFtZScsIHtcbiAgICAgIHR5cGU6ICdTdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246IGBFQ1IgcmVwb3NpdG9yeSBuYW1lIGFuZCB0YWcgYXNzZXQgXCIke3RoaXMubm9kZS5wYXRofVwiYCxcbiAgICB9KTtcblxuICAgIGNvbnN0IGFzc2V0OiBjeGFwaS5Db250YWluZXJJbWFnZUFzc2V0TWV0YWRhdGFFbnRyeSA9IHtcbiAgICAgIGlkOiB0aGlzLm5vZGUudW5pcXVlSWQsXG4gICAgICBwYWNrYWdpbmc6ICdjb250YWluZXItaW1hZ2UnLFxuICAgICAgcGF0aDogdGhpcy5kaXJlY3RvcnksXG4gICAgICBzb3VyY2VIYXNoOiB0aGlzLnNvdXJjZUhhc2gsXG4gICAgICBpbWFnZU5hbWVQYXJhbWV0ZXI6IGltYWdlTmFtZVBhcmFtZXRlci5sb2dpY2FsSWQsXG4gICAgICByZXBvc2l0b3J5TmFtZTogcHJvcHMucmVwb3NpdG9yeU5hbWUsXG4gICAgICBidWlsZEFyZ3M6IHByb3BzLmJ1aWxkQXJnc1xuICAgIH07XG5cbiAgICB0aGlzLm5vZGUuYWRkTWV0YWRhdGEoY3hhcGkuQVNTRVRfTUVUQURBVEEsIGFzc2V0KTtcblxuICAgIC8vIFBhcnNlIHJlcG9zaXRvcnkgbmFtZSBhbmQgdGFnIGZyb20gdGhlIHBhcmFtZXRlciAoPFJFUE9fTkFNRT5Ac2hhMjU2OjxUQUc+KVxuICAgIC8vIEV4YW1wbGU6IGNkay9jZGtleGFtcGxlaW1hZ2ViMmQ3ZjUwNEBzaGEyNTY6NzJjNGY5NTYzNzlhNDNiNTYyM2Q1MjlkZGQ5NjlmNjgyNmRkZTk0NGQ2MjIxZjQ0NWZmM2U3YWRkOTg3NTUwMFxuICAgIGNvbnN0IGNvbXBvbmVudHMgPSBjZGsuRm4uc3BsaXQoJ0BzaGEyNTY6JywgaW1hZ2VOYW1lUGFyYW1ldGVyLnN0cmluZ1ZhbHVlKTtcbiAgICBjb25zdCByZXBvc2l0b3J5TmFtZSA9IGNkay5Gbi5zZWxlY3QoMCwgY29tcG9uZW50cykudG9TdHJpbmcoKTtcbiAgICBjb25zdCBpbWFnZVNoYSA9IGNkay5Gbi5zZWxlY3QoMSwgY29tcG9uZW50cykudG9TdHJpbmcoKTtcblxuICAgIC8vIFJlcXVpcmUgdGhhdCByZXBvc2l0b3J5IGFkb3B0aW9uIGhhcHBlbnMgZmlyc3QsIHNvIHdlIHJvdXRlIHRoZVxuICAgIC8vIGlucHV0IEFSTiBpbnRvIHRoZSBDdXN0b20gUmVzb3VyY2UgYW5kIHRoZW4gZ2V0IHRoZSBVUkkgd2hpY2ggd2UgdXNlIHRvXG4gICAgLy8gcmVmZXIgdG8gdGhlIGltYWdlIEZST00gdGhlIEN1c3RvbSBSZXNvdXJjZS5cbiAgICAvL1xuICAgIC8vIElmIGFkb3B0aW9uIGZhaWxzIChiZWNhdXNlIHRoZSByZXBvc2l0b3J5IG1pZ2h0IGJlIHR3aWNlLWFkb3B0ZWQpLCB3ZVxuICAgIC8vIGhhdmVuJ3QgYWxyZWFkeSBzdGFydGVkIHVzaW5nIHRoZSBpbWFnZS5cbiAgICB0aGlzLnJlcG9zaXRvcnkgPSBuZXcgQWRvcHRlZFJlcG9zaXRvcnkodGhpcywgJ0Fkb3B0UmVwb3NpdG9yeScsIHsgcmVwb3NpdG9yeU5hbWUgfSk7XG4gICAgdGhpcy5pbWFnZVVyaSA9IGAke3RoaXMucmVwb3NpdG9yeS5yZXBvc2l0b3J5VXJpfUBzaGEyNTY6JHtpbWFnZVNoYX1gO1xuICAgIHRoaXMuYXJ0aWZhY3RIYXNoID0gaW1hZ2VTaGE7XG4gIH1cbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/assets-docker/lib/index.d.ts b/packages/@aws-cdk/assets-docker/lib/index.d.ts new file mode 100644 index 0000000000000..579fee533587d --- /dev/null +++ b/packages/@aws-cdk/assets-docker/lib/index.d.ts @@ -0,0 +1 @@ +export * from './image-asset'; diff --git a/packages/@aws-cdk/assets-docker/lib/index.js b/packages/@aws-cdk/assets-docker/lib/index.js new file mode 100644 index 0000000000000..837d8c8592eb4 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/lib/index.js @@ -0,0 +1,7 @@ +"use strict"; +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +Object.defineProperty(exports, "__esModule", { value: true }); +__export(require("./image-asset")); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG1DQUE4QiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vaW1hZ2UtYXNzZXQnO1xuIl19 \ No newline at end of file diff --git a/packages/@aws-cdk/assets-docker/test/integ.assets-docker.d.ts b/packages/@aws-cdk/assets-docker/test/integ.assets-docker.d.ts new file mode 100644 index 0000000000000..cb0ff5c3b541f --- /dev/null +++ b/packages/@aws-cdk/assets-docker/test/integ.assets-docker.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/@aws-cdk/assets-docker/test/integ.assets-docker.js b/packages/@aws-cdk/assets-docker/test/integ.assets-docker.js new file mode 100644 index 0000000000000..349f11ff43a82 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/test/integ.assets-docker.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const cdk = require("@aws-cdk/cdk"); +const path = require("path"); +const assets = require("../lib"); +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integ-assets-docker'); +const asset = new assets.DockerImageAsset(stack, 'DockerImage', { + directory: path.join(__dirname, 'demo-image'), +}); +new cdk.CfnOutput(stack, 'ArtifactHash', { value: asset.artifactHash }); +new cdk.CfnOutput(stack, 'ImageUri', { value: asset.imageUri }); +app.synth(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZWcuYXNzZXRzLWRvY2tlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImludGVnLmFzc2V0cy1kb2NrZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxvQ0FBcUM7QUFDckMsNkJBQThCO0FBQzlCLGlDQUFrQztBQUVsQyxNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUMxQixNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLHFCQUFxQixDQUFDLENBQUM7QUFFeEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxNQUFNLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLGFBQWEsRUFBRTtJQUM5RCxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDO0NBQzlDLENBQUMsQ0FBQztBQUVILElBQUksR0FBRyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsY0FBYyxFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO0FBQ3hFLElBQUksR0FBRyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsVUFBVSxFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0FBRWhFLEdBQUcsQ0FBQyxLQUFLLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjZGsgPSByZXF1aXJlKCdAYXdzLWNkay9jZGsnKTtcbmltcG9ydCBwYXRoID0gcmVxdWlyZSgncGF0aCcpO1xuaW1wb3J0IGFzc2V0cyA9IHJlcXVpcmUoJy4uL2xpYicpO1xuXG5jb25zdCBhcHAgPSBuZXcgY2RrLkFwcCgpO1xuY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKGFwcCwgJ2ludGVnLWFzc2V0cy1kb2NrZXInKTtcblxuY29uc3QgYXNzZXQgPSBuZXcgYXNzZXRzLkRvY2tlckltYWdlQXNzZXQoc3RhY2ssICdEb2NrZXJJbWFnZScsIHtcbiAgZGlyZWN0b3J5OiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnZGVtby1pbWFnZScpLFxufSk7XG5cbm5ldyBjZGsuQ2ZuT3V0cHV0KHN0YWNrLCAnQXJ0aWZhY3RIYXNoJywgeyB2YWx1ZTogYXNzZXQuYXJ0aWZhY3RIYXNoIH0pO1xubmV3IGNkay5DZm5PdXRwdXQoc3RhY2ssICdJbWFnZVVyaScsIHsgdmFsdWU6IGFzc2V0LmltYWdlVXJpIH0pO1xuXG5hcHAuc3ludGgoKTtcbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/assets-docker/test/test.adpot-repo.d.ts b/packages/@aws-cdk/assets-docker/test/test.adpot-repo.d.ts new file mode 100644 index 0000000000000..5cde3dfde89e1 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/test/test.adpot-repo.d.ts @@ -0,0 +1,11 @@ +import { Test } from 'nodeunit'; +declare const _default: { + 'exercise handler create with policy'(test: Test): Promise; + 'exercise handler create with policy with object statement'(test: Test): Promise; + 'exercise handler create with policy with array statement'(test: Test): Promise; + 'exercise handler create'(test: Test): Promise; + 'exercise handler delete'(test: Test): Promise; + 'exercise "delete" handler when repository doesnt exist'(test: Test): Promise; + 'exercise "create" handler when repository doesnt exist'(test: Test): Promise; +}; +export = _default; diff --git a/packages/@aws-cdk/assets-docker/test/test.adpot-repo.js b/packages/@aws-cdk/assets-docker/test/test.adpot-repo.js new file mode 100644 index 0000000000000..2f9f248970031 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/test/test.adpot-repo.js @@ -0,0 +1,329 @@ +"use strict"; +const path = require("path"); +const proxyquire = require("proxyquire"); +let ecrMock; +function ECRWithEmptyPolicy() { + ecrMock = new ECR({ asdf: 'asdf' }); + return ecrMock; +} +function ECRWithOwningPolicy() { + return new ECR({ + Statement: [ + { + Sid: 'StackId', + Effect: "Deny", + Action: "OwnedBy:CDKStack", + Principal: "*" + } + ] + }); +} +function ECRWithRepositoryNotFound() { + const ecr = new ECR({}); + ecr.shouldThrowNotFound = true; + return ecr; +} +class ECR { + constructor(policy) { + this.policy = policy; + this.shouldThrowNotFound = false; + } + getRepositoryPolicy() { + const self = this; + return { + async promise() { + if (self.shouldThrowNotFound) { + return self.throwNotFound(); + } + return { policyText: JSON.stringify(self.policy) }; + } + }; + } + setRepositoryPolicy(req) { + const self = this; + this.lastSetRepositoryPolicyRequest = req; + return { + async promise() { + if (self.shouldThrowNotFound) { + return self.throwNotFound(); + } + return; + } + }; + } + listImages() { + return { + async promise() { + return { imageIds: [] }; + } + }; + } + batchDeleteImage() { + const self = this; + return { + async promise() { + if (self.shouldThrowNotFound) { + return self.throwNotFound(); + } + return {}; + } + }; + } + deleteRepository() { + const self = this; + return { + async promise() { + if (self.shouldThrowNotFound) { + return self.throwNotFound(); + } + return {}; + } + }; + } + throwNotFound() { + const err = new Error('Simulated RepositoryPolicyNotFoundException'); + err.code = 'RepositoryPolicyNotFoundException'; + throw err; + } +} +module.exports = { + async 'exercise handler create with policy'(test) { + const handler = proxyquire(path.resolve(__dirname, '..', 'lib', 'adopt-repository', 'handler'), { + 'aws-sdk': { + '@noCallThru': true, + "ECR": ECRWithEmptyPolicy, + } + }); + let output; + async function response(responseStatus, reason, physId, data) { + output = { responseStatus, reason, physId, data }; + } + await handler.handler({ + StackId: 'StackId', + ResourceProperties: { + RepositoryName: 'RepositoryName', + PolicyDocument: { + Version: '2008-10-01', + My: 'Document' + } + }, + RequestType: 'Create', + ResponseURL: 'https://localhost/test' + }, { + logStreamName: 'xyz', + }, undefined, response); + test.deepEqual(JSON.parse(ecrMock.lastSetRepositoryPolicyRequest.policyText), { + My: "Document", + Version: '2008-10-01', + Statement: [ + { Sid: "StackId", Effect: "Deny", Action: "OwnedBy:CDKStack", Principal: "*" } + ] + }); + test.deepEqual(output, { + responseStatus: 'SUCCESS', + reason: 'OK', + physId: 'RepositoryName', + data: { + RepositoryName: 'RepositoryName' + } + }); + test.done(); + }, + async 'exercise handler create with policy with object statement'(test) { + const handler = proxyquire(path.resolve(__dirname, '..', 'lib', 'adopt-repository', 'handler'), { + 'aws-sdk': { + '@noCallThru': true, + "ECR": ECRWithEmptyPolicy, + } + }); + let output; + async function response(responseStatus, reason, physId, data) { + output = { responseStatus, reason, physId, data }; + } + await handler.handler({ + StackId: 'StackId', + ResourceProperties: { + RepositoryName: 'RepositoryName', + PolicyDocument: { + Statement: { Action: 'boom' } + } + }, + RequestType: 'Create', + ResponseURL: 'https://localhost/test' + }, { + logStreamName: 'xyz', + }, undefined, response); + test.deepEqual(JSON.parse(ecrMock.lastSetRepositoryPolicyRequest.policyText), { + Version: '2008-10-17', + Statement: [ + { Action: 'boom' }, + { Sid: "StackId", Effect: "Deny", Action: "OwnedBy:CDKStack", Principal: "*" } + ] + }); + test.deepEqual(output, { + responseStatus: 'SUCCESS', + reason: 'OK', + physId: 'RepositoryName', + data: { + RepositoryName: 'RepositoryName' + } + }); + test.done(); + }, + async 'exercise handler create with policy with array statement'(test) { + const handler = proxyquire(path.resolve(__dirname, '..', 'lib', 'adopt-repository', 'handler'), { + 'aws-sdk': { + '@noCallThru': true, + "ECR": ECRWithEmptyPolicy, + } + }); + let output; + async function response(responseStatus, reason, physId, data) { + output = { responseStatus, reason, physId, data }; + } + await handler.handler({ + StackId: 'StackId', + ResourceProperties: { + RepositoryName: 'RepositoryName', + PolicyDocument: { + Statement: [{ Action: 'boom' }, { Resource: "foo" }] + } + }, + RequestType: 'Create', + ResponseURL: 'https://localhost/test' + }, { + logStreamName: 'xyz', + }, undefined, response); + test.deepEqual(JSON.parse(ecrMock.lastSetRepositoryPolicyRequest.policyText), { + Version: '2008-10-17', + Statement: [ + { Action: "boom" }, + { Resource: "foo" }, + { Sid: "StackId", Effect: "Deny", Action: "OwnedBy:CDKStack", Principal: "*" } + ] + }); + test.deepEqual(output, { + responseStatus: 'SUCCESS', + reason: 'OK', + physId: 'RepositoryName', + data: { + RepositoryName: 'RepositoryName' + } + }); + test.done(); + }, + async 'exercise handler create'(test) { + const handler = proxyquire(path.resolve(__dirname, '..', 'lib', 'adopt-repository', 'handler'), { + 'aws-sdk': { + '@noCallThru': true, + "ECR": ECRWithEmptyPolicy, + } + }); + let output; + async function response(responseStatus, reason, physId, data) { + output = { responseStatus, reason, physId, data }; + } + await handler.handler({ + StackId: 'StackId', + ResourceProperties: { + RepositoryName: 'RepositoryName', + }, + RequestType: 'Create', + ResponseURL: 'https://localhost/test' + }, { + logStreamName: 'xyz', + }, undefined, response); + test.deepEqual(output, { + responseStatus: 'SUCCESS', + reason: 'OK', + physId: 'RepositoryName', + data: { + RepositoryName: 'RepositoryName' + } + }); + test.done(); + }, + async 'exercise handler delete'(test) { + const handler = proxyquire(path.resolve(__dirname, '..', 'lib', 'adopt-repository', 'handler'), { + 'aws-sdk': { '@noCallThru': true, "ECR": ECRWithOwningPolicy } + }); + let output; + async function response(responseStatus, reason, physId, data) { + output = { responseStatus, reason, physId, data }; + } + await handler.handler({ + StackId: 'StackId', + ResourceProperties: { + RepositoryName: 'RepositoryName', + }, + RequestType: 'Delete', + ResponseURL: 'https://localhost/test' + }, { + logStreamName: 'xyz', + }, undefined, response); + test.deepEqual(output, { + responseStatus: 'SUCCESS', + reason: 'OK', + physId: 'RepositoryName', + data: { + RepositoryName: 'RepositoryName' + } + }); + test.done(); + }, + async 'exercise "delete" handler when repository doesnt exist'(test) { + const handler = proxyquire(path.resolve(__dirname, '..', 'lib', 'adopt-repository', 'handler'), { + 'aws-sdk': { '@noCallThru': true, "ECR": ECRWithRepositoryNotFound } + }); + let output; + async function response(responseStatus, reason, physId, data) { + output = { responseStatus, reason, physId, data }; + } + await handler.handler({ + StackId: 'StackId', + ResourceProperties: { + RepositoryName: 'RepositoryName', + }, + RequestType: 'Delete', + ResponseURL: 'https://localhost/test' + }, { + logStreamName: 'xyz', + }, undefined, response); + test.deepEqual(output, { + responseStatus: 'SUCCESS', + reason: 'OK', + physId: 'RepositoryName', + data: { + RepositoryName: 'RepositoryName' + } + }); + test.done(); + }, + async 'exercise "create" handler when repository doesnt exist'(test) { + const handler = proxyquire(path.resolve(__dirname, '..', 'lib', 'adopt-repository', 'handler'), { + 'aws-sdk': { '@noCallThru': true, "ECR": ECRWithRepositoryNotFound } + }); + let output; + async function response(responseStatus, reason, physId, data) { + output = { responseStatus, reason, physId, data }; + } + await handler.handler({ + StackId: 'StackId', + ResourceProperties: { + RepositoryName: 'RepositoryName', + }, + RequestType: 'Create', + ResponseURL: 'https://localhost/test' + }, { + logStreamName: 'xyz', + }, undefined, response); + test.deepEqual(output, { + responseStatus: 'FAILED', + reason: 'Simulated RepositoryPolicyNotFoundException', + physId: 'xyz', + data: {} + }); + test.done(); + }, +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5hZHBvdC1yZXBvLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGVzdC5hZHBvdC1yZXBvLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSw2QkFBOEI7QUFDOUIseUNBQTBDO0FBRTFDLElBQUksT0FBWSxDQUFDO0FBd1JqQixTQUFTLGtCQUFrQjtJQUN6QixPQUFPLEdBQUcsSUFBSSxHQUFHLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUNwQyxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDO0FBRUQsU0FBUyxtQkFBbUI7SUFDMUIsT0FBTyxJQUFJLEdBQUcsQ0FBQztRQUNiLFNBQVMsRUFBRTtZQUNUO2dCQUNFLEdBQUcsRUFBRSxTQUFTO2dCQUNkLE1BQU0sRUFBRSxNQUFNO2dCQUNkLE1BQU0sRUFBRSxrQkFBa0I7Z0JBQzFCLFNBQVMsRUFBRSxHQUFHO2FBQ2Y7U0FDRjtLQUNGLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxTQUFTLHlCQUF5QjtJQUNoQyxNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN4QixHQUFHLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0lBQy9CLE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVELE1BQU0sR0FBRztJQUlQLFlBQTJCLE1BQVc7UUFBWCxXQUFNLEdBQU4sTUFBTSxDQUFLO1FBRi9CLHdCQUFtQixHQUFHLEtBQUssQ0FBQztJQUduQyxDQUFDO0lBRU0sbUJBQW1CO1FBQ3hCLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQztRQUNsQixPQUFPO1lBQ0wsS0FBSyxDQUFDLE9BQU87Z0JBQ1gsSUFBSSxJQUFJLENBQUMsbUJBQW1CLEVBQUU7b0JBQUUsT0FBTyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7aUJBQUU7Z0JBQzlELE9BQU8sRUFBRSxVQUFVLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMs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QUNqQztZQUNELFdBQVcsRUFBRSxRQUFRO1lBQ3JCLFdBQVcsRUFBRSx3QkFBd0I7U0FDdEMsRUFBRTtZQUNELGFBQWEsRUFBRSxLQUFLO1NBQ3JCLEVBQUUsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRXhCLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFO1lBQ3JCLGNBQWMsRUFBRSxRQUFRO1lBQ3hCLE1BQU0sRUFBRSw2Q0FBNkM7WUFDckQsTUFBTSxFQUFFLEtBQUs7WUFDYixJQUFJLEVBQUUsRUFBRztTQUNWLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNkLENBQUM7Q0FDRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVGVzdCB9IGZyb20gJ25vZGV1bml0JztcbmltcG9ydCBwYXRoID0gcmVxdWlyZSgncGF0aCcpO1xuaW1wb3J0IHByb3h5cXVpcmUgPSByZXF1aXJlKCdwcm94eXF1aXJlJyk7XG5cbmxldCBlY3JNb2NrOiBhbnk7XG5cbmV4cG9ydCA9IHtcbiAgYXN5bmMgJ2V4ZXJjaXNlIGhhbmRsZXIgY3JlYXRlIHdpdGggcG9saWN5Jyh0ZXN0OiBUZXN0KSB7XG4gICAgY29uc3QgaGFuZGxlciA9IHByb3h5cXVpcmUocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uJywgJ2xpYicsICdhZG9wdC1yZXBvc2l0b3J5JywgJ2hhbmRsZXInKSwge1xuICAgICAgJ2F3cy1zZGsnOiB7XG4gICAgICAgICdAbm9DYWxsVGhydSc6IHRydWUsXG4gICAgICAgIFwiRUNSXCI6IEVDUldpdGhFbXB0eVBvbGljeSxcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGxldCBvdXRwdXQ7XG4gICAgYXN5bmMgZnVuY3Rpb24gcmVzcG9uc2UocmVzcG9uc2VTdGF0dXM6IHN0cmluZywgcmVhc29uOiBzdHJpbmcsIHBoeXNJZDogc3RyaW5nLCBkYXRhOiBhbnkpIHtcbiAgICAgIG91dHB1dCA9IHsgcmVzcG9uc2VTdGF0dXMsIHJlYXNvbiwgcGh5c0lkLCBkYXRhIH07XG4gICAgfVxuXG4gICAgYXdhaXQgaGFuZGxlci5oYW5kbGVyKHtcbiAgICAgIFN0YWNrSWQ6ICdTdGFja0lkJyxcbiAgICAgIFJlc291cmNlUHJvcGVydGllczoge1xuICAgICAgICBSZXBvc2l0b3J5TmFtZTogJ1JlcG9zaXRvcnlOYW1lJyxcbiAgICAgICAgUG9saWN5RG9jdW1lbnQ6IHtcbiAgICAgICAgICBWZXJzaW9uOiAnMjAwOC0xMC0wMScsXG4gICAgICAgICAgTXk6ICdEb2N1bWVudCdcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIFJlcXVlc3RUeXBlOiAnQ3JlYXRlJyxcbiAgICAgIFJlc3BvbnNlVVJMOiAnaHR0cHM6Ly9sb2NhbGhvc3QvdGVzdCdcbiAgICB9LCB7XG4gICAgICBsb2dTdHJlYW1OYW1lOiAneHl6JyxcbiAgICB9LCB1bmRlZmluZWQsIHJlc3BvbnNlKTtcblxuICAgIHRlc3QuZGVlcEVxdWFsKEpTT04ucGFyc2UoZWNyTW9jay5sYXN0U2V0UmVwb3NpdG9yeVBvbGljeVJlcXVlc3QucG9saWN5VGV4dCksIHtcbiAgICAgIE15OiBcIkRvY3VtZW50XCIsXG4gICAgICBWZXJzaW9uOiAnMjAwOC0xMC0wMScsXG4gICAgICBTdGF0ZW1lbnQ6IFtcbiAgICAgICAgeyBTaWQ6IFwiU3RhY2tJZFwiLCBFZmZlY3Q6IFwiRGVueVwiLCBBY3Rpb246IFwiT3duZWRCeTpDREtTdGFja1wiLCBQcmluY2lwYWw6IFwiKlwiIH1cbiAgICAgIF1cbiAgICB9KTtcblxuICAgIHRlc3QuZGVlcEVxdWFsKG91dHB1dCwge1xuICAgICAgcmVzcG9uc2VTdGF0dXM6ICdTVUNDRVNTJyxcbiAgICAgIHJlYXNvbjogJ09LJyxcbiAgICAgIHBoeXNJZDogJ1JlcG9zaXRvcnlOYW1lJyxcbiAgICAgIGRhdGE6IHtcbiAgICAgICAgUmVwb3NpdG9yeU5hbWU6ICdSZXBvc2l0b3J5TmFtZSdcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gIGFzeW5jICdleGVyY2lzZSBoYW5kbGVyIGNyZWF0ZSB3aXRoIHBvbGljeSB3aXRoIG9iamVjdCBzdGF0ZW1lbnQnKHRlc3Q6IFRlc3QpIHtcbiAgICBjb25zdCBoYW5kbGVyID0gcHJveHlxdWlyZShwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi4nLCAnbGliJywgJ2Fkb3B0LXJlcG9zaXRvcnknLCAnaGFuZGxlcicpLCB7XG4gICAgICAnYXdzLXNkayc6IHtcbiAgICAgICAgJ0Bub0NhbGxUaHJ1JzogdHJ1ZSxcbiAgICAgICAgXCJFQ1JcIjogRUNSV2l0aEVtcHR5UG9saWN5LFxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgbGV0IG91dHB1dDtcbiAgICBhc3luYyBmdW5jdGlvbiByZXNwb25zZShyZXNwb25zZVN0YXR1czogc3RyaW5nLCByZWFzb246IHN0cmluZywgcGh5c0lkOiBzdHJpbmcsIGRhdGE6IGFueSkge1xuICAgICAgb3V0cHV0ID0geyByZXNwb25zZVN0YXR1cywgcmVhc29uLCBwaHlzSWQsIGRhdGEgfTtcbiAgICB9XG5cbiAgICBhd2FpdCBoYW5kbGVyLmhhbmRsZXIoe1xuICAgICAgU3RhY2tJZDogJ1N0YWNrSWQnLFxuICAgICAgUmVzb3VyY2VQcm9wZXJ0aWVzOiB7XG4gICAgICAgIFJlcG9zaXRvcnlOYW1lOiAnUmVwb3NpdG9yeU5hbWUnLFxuICAgICAgICBQb2xpY3lEb2N1bWVudDoge1xuICAgICAgICAgIFN0YXRlbWVudDogeyBBY3Rpb246ICdib29tJyB9XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBSZXF1ZXN0VHlwZTogJ0NyZWF0ZScsXG4gICAgICBSZXNwb25zZVVSTDogJ2h0dHBzOi8vbG9jYWxob3N0L3Rlc3QnXG4gICAgfSwge1xuICAgICAgbG9nU3RyZWFtTmFtZTogJ3h5eicsXG4gICAgfSwgdW5kZWZpbmVkLCByZXNwb25zZSk7XG5cbiAgICB0ZXN0LmRlZXBFcXVhbChKU09OLnBhcnNlKGVjck1vY2subGFzdFNldFJlcG9zaXRvcnlQb2xpY3lSZXF1ZXN0LnBvbGljeVRleHQpLCB7XG4gICAgICBWZXJzaW9uOiAnMjAwOC0xMC0xNycsXG4gICAgICBTdGF0ZW1lbnQ6IFtcbiAgICAgICAgeyBBY3Rpb246ICdib29tJyB9LFxuICAgICAgICB7IFNpZDogXCJTdGFja0lkXCIsIEVmZmVjdDogXCJEZW55XCIsIEFjdGlvbjogXCJPd25lZEJ5OkNES1N0YWNrXCIsIFByaW5jaXBhbDogXCIqXCIgfVxuICAgICAgXVxuICAgIH0pO1xuXG4gICAgdGVzdC5kZWVwRXF1YWwob3V0cHV0LCB7XG4gICAgICByZXNwb25zZVN0YXR1czogJ1NVQ0NFU1MnLFxuICAgICAgcmVhc29uOiAnT0snLFxuICAgICAgcGh5c0lkOiAnUmVwb3NpdG9yeU5hbWUnLFxuICAgICAgZGF0YToge1xuICAgICAgICBSZXBvc2l0b3J5TmFtZTogJ1JlcG9zaXRvcnlOYW1lJ1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgYXN5bmMgJ2V4ZXJjaXNlIGhhbmRsZXIgY3JlYXRlIHdpdGggcG9saWN5IHdpdGggYXJyYXkgc3RhdGVtZW50Jyh0ZXN0OiBUZXN0KSB7XG4gICAgY29uc3QgaGFuZGxlciA9IHByb3h5cXVpcmUocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uJywgJ2xpYicsICdhZG9wdC1yZXBvc2l0b3J5JywgJ2hhbmRsZXInKSwge1xuICAgICAgJ2F3cy1zZGsnOiB7XG4gICAgICAgICdAbm9DYWxsVGhydSc6IHRydWUsXG4gICAgICAgIFwiRUNSXCI6IEVDUldpdGhFbXB0eVBvbGljeSxcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGxldCBvdXRwdXQ7XG4gICAgYXN5bmMgZnVuY3Rpb24gcmVzcG9uc2UocmVzcG9uc2VTdGF0dXM6IHN0cmluZywgcmVhc29uOiBzdHJpbmcsIHBoeXNJZDogc3RyaW5nLCBkYXRhOiBhbnkpIHtcbiAgICAgIG91dHB1dCA9IHsgcmVzcG9uc2VTdGF0dXMsIHJlYXNvbiwgcGh5c0lkLCBkYXRhIH07XG4gICAgfVxuXG4gICAgYXdhaXQgaGFuZGxlci5oYW5kbGVyKHtcbiAgICAgIFN0YWNrSWQ6ICdTdGFja0lkJyxcbiAgICAgIFJlc291cmNlUHJvcGVydGllczoge1xuICAgICAgICBSZXBvc2l0b3J5TmFtZTogJ1JlcG9zaXRvcnlOYW1lJyxcbiAgICAgICAgUG9saWN5RG9jdW1lbnQ6IHtcbiAgICAgICAgICBTdGF0ZW1lbnQ6IFsgeyBBY3Rpb246ICdib29tJyB9LCB7IFJlc291cmNlOiBcImZvb1wiIH0gIF1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIFJlcXVlc3RUeXBlOiAnQ3JlYXRlJyxcbiAgICAgIFJlc3BvbnNlVVJMOiAnaHR0cHM6Ly9sb2NhbGhvc3QvdGVzdCdcbiAgICB9LCB7XG4gICAgICBsb2dTdHJlYW1OYW1lOiAneHl6JyxcbiAgICB9LCB1bmRlZmluZWQsIHJlc3BvbnNlKTtcblxuICAgIHRlc3QuZGVlcEVxdWFsKEpTT04ucGFyc2UoZWNyTW9jay5sYXN0U2V0UmVwb3NpdG9yeVBvbGljeVJlcXVlc3QucG9saWN5VGV4dCksIHtcbiAgICAgIFZlcnNpb246ICcyMDA4LTEwLTE3JyxcbiAgICAgIFN0YXRlbWVudDogW1xuICAgICAgICB7IEFjdGlvbjogXCJib29tXCIgfSxcbiAgICAgICAgeyBSZXNvdXJjZTogXCJmb29cIiB9LFxuICAgICAgICB7IFNpZDogXCJTdGFja0lkXCIsIEVmZmVjdDogXCJEZW55XCIsIEFjdGlvbjogXCJPd25lZEJ5OkNES1N0YWNrXCIsIFByaW5jaXBhbDogXCIqXCIgfVxuICAgICAgXVxuICAgIH0pO1xuXG4gICAgdGVzdC5kZWVwRXF1YWwob3V0cHV0LCB7XG4gICAgICByZXNwb25zZVN0YXR1czogJ1NVQ0NFU1MnLFxuICAgICAgcmVhc29uOiAnT0snLFxuICAgICAgcGh5c0lkOiAnUmVwb3NpdG9yeU5hbWUnLFxuICAgICAgZGF0YToge1xuICAgICAgICBSZXBvc2l0b3J5TmFtZTogJ1JlcG9zaXRvcnlOYW1lJ1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgYXN5bmMgJ2V4ZXJjaXNlIGhhbmRsZXIgY3JlYXRlJyh0ZXN0OiBUZXN0KSB7XG4gICAgY29uc3QgaGFuZGxlciA9IHByb3h5cXVpcmUocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uJywgJ2xpYicsICdhZG9wdC1yZXBvc2l0b3J5JywgJ2hhbmRsZXInKSwge1xuICAgICAgJ2F3cy1zZGsnOiB7XG4gICAgICAgICdAbm9DYWxsVGhydSc6IHRydWUsXG4gICAgICAgIFwiRUNSXCI6IEVDUldpdGhFbXB0eVBvbGljeSxcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGxldCBvdXRwdXQ7XG4gICAgYXN5bmMgZnVuY3Rpb24gcmVzcG9uc2UocmVzcG9uc2VTdGF0dXM6IHN0cmluZywgcmVhc29uOiBzdHJpbmcsIHBoeXNJZDogc3RyaW5nLCBkYXRhOiBhbnkpIHtcbiAgICAgIG91dHB1dCA9IHsgcmVzcG9uc2VTdGF0dXMsIHJlYXNvbiwgcGh5c0lkLCBkYXRhIH07XG4gICAgfVxuXG4gICAgYXdhaXQgaGFuZGxlci5oYW5kbGVyKHtcbiAgICAgIFN0YWNrSWQ6ICdTdGFja0lkJyxcbiAgICAgIFJlc291cmNlUHJvcGVydGllczoge1xuICAgICAgICBSZXBvc2l0b3J5TmFtZTogJ1JlcG9zaXRvcnlOYW1lJyxcbiAgICAgIH0sXG4gICAgICBSZXF1ZXN0VHlwZTogJ0NyZWF0ZScsXG4gICAgICBSZXNwb25zZVVSTDogJ2h0dHBzOi8vbG9jYWxob3N0L3Rlc3QnXG4gICAgfSwge1xuICAgICAgbG9nU3RyZWFtTmFtZTogJ3h5eicsXG4gICAgfSwgdW5kZWZpbmVkLCByZXNwb25zZSk7XG5cbiAgICB0ZXN0LmRlZXBFcXVhbChvdXRwdXQsIHtcbiAgICAgIHJlc3BvbnNlU3RhdHVzOiAnU1VDQ0VTUycsXG4gICAgICByZWFzb246ICdPSycsXG4gICAgICBwaHlzSWQ6ICdSZXBvc2l0b3J5TmFtZScsXG4gICAgICBkYXRhOiB7XG4gICAgICAgIFJlcG9zaXRvcnlOYW1lOiAnUmVwb3NpdG9yeU5hbWUnXG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICBhc3luYyAnZXhlcmNpc2UgaGFuZGxlciBkZWxldGUnKHRlc3Q6IFRlc3QpIHtcbiAgICBjb25zdCBoYW5kbGVyID0gcHJveHlxdWlyZShwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi4nLCAnbGliJywgJ2Fkb3B0LXJlcG9zaXRvcnknLCAnaGFuZGxlcicpLCB7XG4gICAgICAnYXdzLXNkayc6IHsgJ0Bub0NhbGxUaHJ1JzogdHJ1ZSwgXCJFQ1JcIjogRUNSV2l0aE93bmluZ1BvbGljeSB9XG4gICAgfSk7XG5cbiAgICBsZXQgb3V0cHV0O1xuICAgIGFzeW5jIGZ1bmN0aW9uIHJlc3BvbnNlKHJlc3BvbnNlU3RhdHVzOiBzdHJpbmcsIHJlYXNvbjogc3RyaW5nLCBwaHlzSWQ6IHN0cmluZywgZGF0YTogYW55KSB7XG4gICAgICBvdXRwdXQgPSB7IHJlc3BvbnNlU3RhdHVzLCByZWFzb24sIHBoeXNJZCwgZGF0YSB9O1xuICAgIH1cblxuICAgIGF3YWl0IGhhbmRsZXIuaGFuZGxlcih7XG4gICAgICBTdGFja0lkOiAnU3RhY2tJZCcsXG4gICAgICBSZXNvdXJjZVByb3BlcnRpZXM6IHtcbiAgICAgICAgUmVwb3NpdG9yeU5hbWU6ICdSZXBvc2l0b3J5TmFtZScsXG4gICAgICB9LFxuICAgICAgUmVxdWVzdFR5cGU6ICdEZWxldGUnLFxuICAgICAgUmVzcG9uc2VVUkw6ICdodHRwczovL2xvY2FsaG9zdC90ZXN0J1xuICAgIH0sIHtcbiAgICAgIGxvZ1N0cmVhbU5hbWU6ICd4eXonLFxuICAgIH0sIHVuZGVmaW5lZCwgcmVzcG9uc2UpO1xuXG4gICAgdGVzdC5kZWVwRXF1YWwob3V0cHV0LCB7XG4gICAgICByZXNwb25zZVN0YXR1czogJ1NVQ0NFU1MnLFxuICAgICAgcmVhc29uOiAnT0snLFxuICAgICAgcGh5c0lkOiAnUmVwb3NpdG9yeU5hbWUnLFxuICAgICAgZGF0YToge1xuICAgICAgICBSZXBvc2l0b3J5TmFtZTogJ1JlcG9zaXRvcnlOYW1lJ1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgYXN5bmMgJ2V4ZXJjaXNlIFwiZGVsZXRlXCIgaGFuZGxlciB3aGVuIHJlcG9zaXRvcnkgZG9lc250IGV4aXN0Jyh0ZXN0OiBUZXN0KSB7XG4gICAgY29uc3QgaGFuZGxlciA9IHByb3h5cXVpcmUocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uJywgJ2xpYicsICdhZG9wdC1yZXBvc2l0b3J5JywgJ2hhbmRsZXInKSwge1xuICAgICAgJ2F3cy1zZGsnOiB7ICdAbm9DYWxsVGhydSc6IHRydWUsIFwiRUNSXCI6IEVDUldpdGhSZXBvc2l0b3J5Tm90Rm91bmQgfVxuICAgIH0pO1xuXG4gICAgbGV0IG91dHB1dDtcbiAgICBhc3luYyBmdW5jdGlvbiByZXNwb25zZShyZXNwb25zZVN0YXR1czogc3RyaW5nLCByZWFzb246IHN0cmluZywgcGh5c0lkOiBzdHJpbmcsIGRhdGE6IGFueSkge1xuICAgICAgb3V0cHV0ID0geyByZXNwb25zZVN0YXR1cywgcmVhc29uLCBwaHlzSWQsIGRhdGEgfTtcbiAgICB9XG5cbiAgICBhd2FpdCBoYW5kbGVyLmhhbmRsZXIoe1xuICAgICAgU3RhY2tJZDogJ1N0YWNrSWQnLFxuICAgICAgUmVzb3VyY2VQcm9wZXJ0aWVzOiB7XG4gICAgICAgIFJlcG9zaXRvcnlOYW1lOiAnUmVwb3NpdG9yeU5hbWUnLFxuICAgICAgfSxcbiAgICAgIFJlcXVlc3RUeXBlOiAnRGVsZXRlJyxcbiAgICAgIFJlc3BvbnNlVVJMOiAnaHR0cHM6Ly9sb2NhbGhvc3QvdGVzdCdcbiAgICB9LCB7XG4gICAgICBsb2dTdHJlYW1OYW1lOiAneHl6JyxcbiAgICB9LCB1bmRlZmluZWQsIHJlc3BvbnNlKTtcblxuICAgIHRlc3QuZGVlcEVxdWFsKG91dHB1dCwge1xuICAgICAgcmVzcG9uc2VTdGF0dXM6ICdTVUNDRVNTJyxcbiAgICAgIHJlYXNvbjogJ09LJyxcbiAgICAgIHBoeXNJZDogJ1JlcG9zaXRvcnlOYW1lJyxcbiAgICAgIGRhdGE6IHtcbiAgICAgICAgUmVwb3NpdG9yeU5hbWU6ICdSZXBvc2l0b3J5TmFtZSdcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gIGFzeW5jICdleGVyY2lzZSBcImNyZWF0ZVwiIGhhbmRsZXIgd2hlbiByZXBvc2l0b3J5IGRvZXNudCBleGlzdCcodGVzdDogVGVzdCkge1xuICAgIGNvbnN0IGhhbmRsZXIgPSBwcm94eXF1aXJlKHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuLicsICdsaWInLCAnYWRvcHQtcmVwb3NpdG9yeScsICdoYW5kbGVyJyksIHtcbiAgICAgICdhd3Mtc2RrJzogeyAnQG5vQ2FsbFRocnUnOiB0cnVlLCBcIkVDUlwiOiBFQ1JXaXRoUmVwb3NpdG9yeU5vdEZvdW5kIH1cbiAgICB9KTtcblxuICAgIGxldCBvdXRwdXQ7XG4gICAgYXN5bmMgZnVuY3Rpb24gcmVzcG9uc2UocmVzcG9uc2VTdGF0dXM6IHN0cmluZywgcmVhc29uOiBzdHJpbmcsIHBoeXNJZDogc3RyaW5nLCBkYXRhOiBhbnkpIHtcbiAgICAgIG91dHB1dCA9IHsgcmVzcG9uc2VTdGF0dXMsIHJlYXNvbiwgcGh5c0lkLCBkYXRhIH07XG4gICAgfVxuXG4gICAgYXdhaXQgaGFuZGxlci5oYW5kbGVyKHtcbiAgICAgIFN0YWNrSWQ6ICdTdGFja0lkJyxcbiAgICAgIFJlc291cmNlUHJvcGVydGllczoge1xuICAgICAgICBSZXBvc2l0b3J5TmFtZTogJ1JlcG9zaXRvcnlOYW1lJyxcbiAgICAgIH0sXG4gICAgICBSZXF1ZXN0VHlwZTogJ0NyZWF0ZScsXG4gICAgICBSZXNwb25zZVVSTDogJ2h0dHBzOi8vbG9jYWxob3N0L3Rlc3QnXG4gICAgfSwge1xuICAgICAgbG9nU3RyZWFtTmFtZTogJ3h5eicsXG4gICAgfSwgdW5kZWZpbmVkLCByZXNwb25zZSk7XG5cbiAgICB0ZXN0LmRlZXBFcXVhbChvdXRwdXQsIHtcbiAgICAgIHJlc3BvbnNlU3RhdHVzOiAnRkFJTEVEJyxcbiAgICAgIHJlYXNvbjogJ1NpbXVsYXRlZCBSZXBvc2l0b3J5UG9saWN5Tm90Rm91bmRFeGNlcHRpb24nLFxuICAgICAgcGh5c0lkOiAneHl6JyxcbiAgICAgIGRhdGE6IHsgfVxuICAgIH0pO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG59O1xuXG5mdW5jdGlvbiBFQ1JXaXRoRW1wdHlQb2xpY3koKSB7XG4gIGVjck1vY2sgPSBuZXcgRUNSKHsgYXNkZjogJ2FzZGYnIH0pO1xuICByZXR1cm4gZWNyTW9jaztcbn1cblxuZnVuY3Rpb24gRUNSV2l0aE93bmluZ1BvbGljeSgpIHtcbiAgcmV0dXJuIG5ldyBFQ1Ioe1xuICAgIFN0YXRlbWVudDogW1xuICAgICAge1xuICAgICAgICBTaWQ6ICdTdGFja0lkJyxcbiAgICAgICAgRWZmZWN0OiBcIkRlbnlcIixcbiAgICAgICAgQWN0aW9uOiBcIk93bmVkQnk6Q0RLU3RhY2tcIixcbiAgICAgICAgUHJpbmNpcGFsOiBcIipcIlxuICAgICAgfVxuICAgIF1cbiAgfSk7XG59XG5cbmZ1bmN0aW9uIEVDUldpdGhSZXBvc2l0b3J5Tm90Rm91bmQoKSB7XG4gIGNvbnN0IGVjciA9IG5ldyBFQ1Ioe30pO1xuICBlY3Iuc2hvdWxkVGhyb3dOb3RGb3VuZCA9IHRydWU7XG4gIHJldHVybiBlY3I7XG59XG5cbmNsYXNzIEVDUiB7XG4gIHB1YmxpYyBsYXN0U2V0UmVwb3NpdG9yeVBvbGljeVJlcXVlc3Q6IGFueTtcbiAgcHVibGljIHNob3VsZFRocm93Tm90Rm91bmQgPSBmYWxzZTtcblxuICBwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSBwb2xpY3k6IGFueSkge1xuICB9XG5cbiAgcHVibGljIGdldFJlcG9zaXRvcnlQb2xpY3koKSB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFzeW5jIHByb21pc2UoKSB7XG4gICAgICAgIGlmIChzZWxmLnNob3VsZFRocm93Tm90Rm91bmQpIHsgcmV0dXJuIHNlbGYudGhyb3dOb3RGb3VuZCgpOyB9XG4gICAgICAgIHJldHVybiB7IHBvbGljeVRleHQ6IEpTT04uc3RyaW5naWZ5KHNlbGYucG9saWN5KSB9O1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBwdWJsaWMgc2V0UmVwb3NpdG9yeVBvbGljeShyZXE6IGFueSkge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgIHRoaXMubGFzdFNldFJlcG9zaXRvcnlQb2xpY3lSZXF1ZXN0ID0gcmVxO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGFzeW5jIHByb21pc2UoKSB7XG4gICAgICAgIGlmIChzZWxmLnNob3VsZFRocm93Tm90Rm91bmQpIHsgcmV0dXJuIHNlbGYudGhyb3dOb3RGb3VuZCgpOyB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgcHVibGljIGxpc3RJbWFnZXMoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFzeW5jIHByb21pc2UoKSB7XG4gICAgICAgIHJldHVybiB7IGltYWdlSWRzOiBbXSB9O1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBwdWJsaWMgYmF0Y2hEZWxldGVJbWFnZSgpIHtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICByZXR1cm4ge1xuICAgICAgYXN5bmMgcHJvbWlzZSgpIHtcbiAgICAgICAgaWYgKHNlbGYuc2hvdWxkVGhyb3dOb3RGb3VuZCkgeyByZXR1cm4gc2VsZi50aHJvd05vdEZvdW5kKCk7IH1cbiAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBwdWJsaWMgZGVsZXRlUmVwb3NpdG9yeSgpIHtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICByZXR1cm4ge1xuICAgICAgYXN5bmMgcHJvbWlzZSgpIHtcbiAgICAgICAgaWYgKHNlbGYuc2hvdWxkVGhyb3dOb3RGb3VuZCkgeyByZXR1cm4gc2VsZi50aHJvd05vdEZvdW5kKCk7IH1cbiAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHRocm93Tm90Rm91bmQoKSB7XG4gICAgY29uc3QgZXJyID0gbmV3IEVycm9yKCdTaW11bGF0ZWQgUmVwb3NpdG9yeVBvbGljeU5vdEZvdW5kRXhjZXB0aW9uJyk7XG4gICAgKGVyciBhcyBhbnkpLmNvZGUgPSAnUmVwb3NpdG9yeVBvbGljeU5vdEZvdW5kRXhjZXB0aW9uJztcbiAgICB0aHJvdyBlcnI7XG4gIH1cbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/assets-docker/test/test.image-asset.d.ts b/packages/@aws-cdk/assets-docker/test/test.image-asset.d.ts new file mode 100644 index 0000000000000..b64d61c49d36a --- /dev/null +++ b/packages/@aws-cdk/assets-docker/test/test.image-asset.d.ts @@ -0,0 +1,11 @@ +import { Test } from 'nodeunit'; +declare const _default: { + 'test instantiating Asset Image'(test: Test): void; + 'with build args'(test: Test): void; + 'asset.repository.grantPull can be used to grant a principal permissions to use the image'(test: Test): void; + 'asset.repository.addToResourcePolicy can be used to modify the ECR resource policy via the adoption custom resource'(test: Test): void; + 'fails if the directory does not exist'(test: Test): void; + 'fails if the directory does not contain a Dockerfile'(test: Test): void; + 'docker directory is staged if asset staging is enabled'(test: Test): void; +}; +export = _default; diff --git a/packages/@aws-cdk/assets-docker/test/test.image-asset.js b/packages/@aws-cdk/assets-docker/test/test.image-asset.js new file mode 100644 index 0000000000000..e0dca615a7f2d --- /dev/null +++ b/packages/@aws-cdk/assets-docker/test/test.image-asset.js @@ -0,0 +1,156 @@ +"use strict"; +const assert_1 = require("@aws-cdk/assert"); +const iam = require("@aws-cdk/aws-iam"); +const cdk = require("@aws-cdk/cdk"); +const fs = require("fs"); +const path = require("path"); +const lib_1 = require("../lib"); +module.exports = { + 'test instantiating Asset Image'(test) { + // GIVEN + const stack = new cdk.Stack(); + // WHEN + new lib_1.DockerImageAsset(stack, 'Image', { + directory: path.join(__dirname, 'demo-image'), + }); + // THEN + const template = assert_1.SynthUtils.synthesize(stack).template; + test.deepEqual(template.Parameters.ImageImageName5E684353, { + Type: 'String', + Description: 'ECR repository name and tag asset "Image"' + }); + test.done(); + }, + 'with build args'(test) { + // GIVEN + const stack = new cdk.Stack(); + // WHEN + const asset = new lib_1.DockerImageAsset(stack, 'Image', { + directory: path.join(__dirname, 'demo-image'), + buildArgs: { + a: 'b' + } + }); + // THEN + const assetMetadata = asset.node.metadata.find(({ type }) => type === 'aws:cdk:asset'); + test.deepEqual(assetMetadata && assetMetadata.data.buildArgs, { a: 'b' }); + test.done(); + }, + 'asset.repository.grantPull can be used to grant a principal permissions to use the image'(test) { + // GIVEN + const stack = new cdk.Stack(); + const user = new iam.User(stack, 'MyUser'); + const asset = new lib_1.DockerImageAsset(stack, 'Image', { + directory: path.join(__dirname, 'demo-image') + }); + // WHEN + asset.repository.grantPull(user); + // THEN + assert_1.expect(stack).to(assert_1.haveResource('AWS::IAM::Policy', { + PolicyDocument: { + "Statement": [ + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { "Ref": "AWS::Partition" }, + ":ecr:", + { "Ref": "AWS::Region" }, + ":", + { "Ref": "AWS::AccountId" }, + ":repository/", + { "Fn::GetAtt": ["ImageAdoptRepositoryE1E84E35", "RepositoryName"] } + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyUserDefaultPolicy7B897426", + "Users": [ + { + "Ref": "MyUserDC45028B" + } + ] + })); + test.done(); + }, + 'asset.repository.addToResourcePolicy can be used to modify the ECR resource policy via the adoption custom resource'(test) { + // GIVEN + const stack = new cdk.Stack(); + const asset = new lib_1.DockerImageAsset(stack, 'Image', { + directory: path.join(__dirname, 'demo-image') + }); + // WHEN + asset.repository.addToResourcePolicy(new iam.PolicyStatement() + .addAction('BOOM') + .addPrincipal(new iam.ServicePrincipal('test.service'))); + // THEN + assert_1.expect(stack).to(assert_1.haveResource('Custom::ECRAdoptedRepository', { + "RepositoryName": { + "Fn::Select": [0, { "Fn::Split": ["@sha256:", { "Ref": "ImageImageName5E684353" }] }] + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "BOOM", + "Effect": "Allow", + "Principal": { + "Service": "test.service" + } + } + ], + "Version": "2012-10-17" + } + })); + test.done(); + }, + 'fails if the directory does not exist'(test) { + // GIVEN + const stack = new cdk.Stack(); + // THEN + test.throws(() => { + new lib_1.DockerImageAsset(stack, 'MyAsset', { + directory: `/does/not/exist/${Math.floor(Math.random() * 9999)}` + }); + }, /Cannot find image directory at/); + test.done(); + }, + 'fails if the directory does not contain a Dockerfile'(test) { + // GIVEN + const stack = new cdk.Stack(); + // THEN + test.throws(() => { + new lib_1.DockerImageAsset(stack, 'Asset', { + directory: __dirname + }); + }, /No 'Dockerfile' found in/); + test.done(); + }, + 'docker directory is staged if asset staging is enabled'(test) { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'stack'); + new lib_1.DockerImageAsset(stack, 'MyAsset', { + directory: path.join(__dirname, 'demo-image') + }); + const session = app.synth(); + test.ok(fs.existsSync(path.join(session.directory, 'asset.1a17a141505ac69144931fe263d130f4612251caa4bbbdaf68a44ed0f405439c/Dockerfile'))); + test.ok(fs.existsSync(path.join(session.directory, 'asset.1a17a141505ac69144931fe263d130f4612251caa4bbbdaf68a44ed0f405439c/index.py'))); + test.done(); + } +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5pbWFnZS1hc3NldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QuaW1hZ2UtYXNzZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDRDQUFtRTtBQUNuRSx3Q0FBeUM7QUFDekMsb0NBQXFDO0FBQ3JDLHlCQUEwQjtBQUUxQiw2QkFBOEI7QUFDOUIsZ0NBQTBDO0FBSTFDLGlCQUFTO0lBQ1AsZ0NBQWdDLENBQUMsSUFBVTtRQUN6QyxRQUFRO1FBQ1IsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFOUIsT0FBTztRQUNQLElBQUksc0JBQWdCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRTtZQUNuQyxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDO1NBQzlDLENBQUMsQ0FBQztRQUVILE9BQU87UUFDUCxNQUFNLFFBQVEsR0FBRyxtQkFBVSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLENBQUM7UUFFdkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLHNCQUFzQixFQUFFO1lBQ3pELElBQUksRUFBRSxRQUFRO1lBQ2QsV0FBVyxFQUFFLDJDQUEyQztTQUN6RCxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDZCxDQUFDO0lBRUQsaUJBQWlCLENBQUMsSUFBVTtRQUMxQixRQUFRO1FBQ1IsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFOUIsT0FBTztRQUNQLE1BQU0sS0FBSyxHQUFHLElBQUksc0JBQWdCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRTtZQUNqRCxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDO1lBQzdDLFNBQVMsRUFBRTtnQkFDVCxDQUFDLEVBQUUsR0FBRzthQUNQO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsT0FBTztRQUNQLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLElBQUksS0FBSyxlQUFlLENBQUMsQ0FBQztRQUN2RixJQUFJLENBQUMsU0FBUyxDQUFDLGFBQWEsSUFBSSxhQUFhLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQzFFLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNkLENBQUM7SUFFRCwwRkFBMEYsQ0FBQyxJQUFVO1FBQ25HLFFBQVE7UUFDUixNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUM5QixNQUFNLElBQUksR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzNDLE1BQU0sS0FBSyxHQUFHLElBQUksc0JBQWdCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRTtZQUNqRCxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDO1NBQzlDLENBQUMsQ0FBQztRQUVILE9BQU87UUFDUCxLQUFLLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVqQyxPQUFPO1FBQ1AsZUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxxQkFBWSxDQUFDLGtCQUFrQixFQUFFO1lBQ2hELGNBQWMsRUFBRTtnQkFDZCxXQUFXLEVBQUU7b0JBQ1g7d0JBQ0UsUUFBUSxFQUFFOzRCQUNSLGlDQUFpQzs0QkFDakMsNEJBQTRCOzRCQUM1QixtQkFBbUI7eUJBQ3BCO3dCQUNELFFBQVEsRUFBRSxPQUFPO3dCQUNqQixVQUFVLEVBQUU7NEJBQ1YsVUFBVSxFQUFFO2dDQUNWLEVBQUU7Z0NBQ0Y7b0NBQ0UsTUFBTTtvQ0FDTixFQUFFLEtBQUssRUFBRSxnQkFBZ0IsRUFBRTtvQ0FDM0IsT0FBTztvQ0FDUCxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUU7b0NBQ3hCLEdBQUc7b0NBQ0gsRUFBRSxLQUFLLEVBQUUsZ0JBQWdCLEVBQUU7b0NBQzNCLGNBQWM7b0NBQ2QsRUFBRSxZQUFZLEVBQUUsQ0FBRSw4QkFBOEIsRUFBRSxnQkFBZ0IsQ0FBRSxFQUFFO2lDQUN2RTs2QkFDRjt5QkFDRjtxQkFDRjtvQkFDRDt3QkFDRSxRQUFRLEVBQUUsMkJBQTJCO3dCQUNyQyxRQUFRLEVBQUUsT0FBTzt3QkFDakIsVUFBVSxFQUFFLEdBQUc7cUJBQ2hCO2lCQUNGO2dCQUNELFNBQVMsRUFBRSxZQUFZO2FBQ3hCO1lBQ0QsWUFBWSxFQUFFLDZCQUE2QjtZQUMzQyxPQUFPLEVBQUU7Z0JBQ1A7b0JBQ0UsS0FBSyxFQUFFLGdCQUFnQjtpQkFDeEI7YUFDRjtTQUNGLENBQUMsQ0FBQyxDQUFDO1FBRUosSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVELHFIQUFxSCxDQUFDLElBQVU7UUFDOUgsUUFBUTtRQUNSLE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzlCLE1BQU0sS0FBSyxHQUFHLElBQUksc0JBQWdCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRTtZQUNqRCxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDO1NBQzlDLENBQUMsQ0FBQztRQUVILE9BQU87UUFDUCxLQUFLLENBQUMsVUFBVSxDQUFDLG1CQUFtQixDQUFDLElBQUksR0FBRyxDQUFDLGVBQWUsRUFBRTthQUMzRCxTQUFTLENBQUMsTUFBTSxDQUFDO2FBQ2pCLFlBQVksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFM0QsT0FBTztRQUNQLGVBQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMscUJBQVksQ0FBQyw4QkFBOEIsRUFBRTtZQUM1RCxnQkFBZ0IsRUFBRTtnQkFDaEIsWUFBWSxFQUFFLENBQUUsQ0FBQyxFQUFFLEVBQUUsV0FBVyxFQUFFLENBQUUsVUFBVSxFQUFFLEVBQUUsS0FBSyxFQUFFLHdCQUF3QixFQUFFLENBQUUsRUFBRSxDQUFFO2FBQzFGO1lBQ0QsZ0JBQWdCLEVBQUU7Z0JBQ2hCLFdBQVcsRUFBRTtvQkFDWDt3QkFDRSxRQUFRLEVBQUUsTUFBTTt3QkFDaEIsUUFBUSxFQUFFLE9BQU87d0JBQ2pCLFdBQVcsRUFBRTs0QkFDWCxTQUFTLEVBQUUsY0FBYzt5QkFDMUI7cUJBQ0Y7aUJBQ0Y7Z0JBQ0QsU0FBUyxFQUFFLFlBQVk7YUFDeEI7U0FDRixDQUFDLENBQUMsQ0FBQztRQUVKLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNkLENBQUM7SUFFRCx1Q0FBdUMsQ0FBQyxJQUFVO1FBQ2hELFFBQVE7UUFDUixNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUU5QixPQUFPO1FBQ1AsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUU7WUFDZixJQUFJLHNCQUFnQixDQUFDLEtBQUssRUFBRSxTQUFTLEVBQUU7Z0JBQ3JDLFNBQVMsRUFBRSxtQkFBbUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUU7YUFDakUsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxFQUFFLGdDQUFnQyxDQUFDLENBQUM7UUFDckMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVELHNEQUFzRCxDQUFDLElBQVU7UUFDL0QsUUFBUTtRQUNSLE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRTlCLE9BQU87UUFDUCxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRTtZQUNmLElBQUksc0JBQWdCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRTtnQkFDbkMsU0FBUyxFQUFFLFNBQVM7YUFDckIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxFQUFFLDBCQUEwQixDQUFDLENBQUM7UUFDL0IsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVELHdEQUF3RCxDQUFDLElBQVU7UUFDakUsTUFBTSxHQUFHLEdBQUcsSUFBSSxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDMUIsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUUxQyxJQUFJLHNCQUFnQixDQUFDLEtBQUssRUFBRSxTQUFTLEVBQUU7WUFDckMsU0FBUyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFlBQVksQ0FBQztTQUM5QyxDQUFDLENBQUM7UUFFSCxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFNUIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxtRkFBbUYsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMxSSxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLGlGQUFpRixDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3hJLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNkLENBQUM7Q0FDRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhwZWN0LCBoYXZlUmVzb3VyY2UsIFN5bnRoVXRpbHMgfSBmcm9tICdAYXdzLWNkay9hc3NlcnQnO1xuaW1wb3J0IGlhbSA9IHJlcXVpcmUoJ0Bhd3MtY2RrL2F3cy1pYW0nKTtcbmltcG9ydCBjZGsgPSByZXF1aXJlKCdAYXdzLWNkay9jZGsnKTtcbmltcG9ydCBmcyA9IHJlcXVpcmUoJ2ZzJyk7XG5pbXBvcnQgeyBUZXN0IH0gZnJvbSAnbm9kZXVuaXQnO1xuaW1wb3J0IHBhdGggPSByZXF1aXJlKCdwYXRoJyk7XG5pbXBvcnQgeyBEb2NrZXJJbWFnZUFzc2V0IH0gZnJvbSAnLi4vbGliJztcblxuLy8gdHNsaW50OmRpc2FibGU6b2JqZWN0LWxpdGVyYWwta2V5LXF1b3Rlc1xuXG5leHBvcnQgPSB7XG4gICd0ZXN0IGluc3RhbnRpYXRpbmcgQXNzZXQgSW1hZ2UnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gICAgLy8gV0hFTlxuICAgIG5ldyBEb2NrZXJJbWFnZUFzc2V0KHN0YWNrLCAnSW1hZ2UnLCB7XG4gICAgICBkaXJlY3Rvcnk6IHBhdGguam9pbihfX2Rpcm5hbWUsICdkZW1vLWltYWdlJyksXG4gICAgfSk7XG5cbiAgICAvLyBUSEVOXG4gICAgY29uc3QgdGVtcGxhdGUgPSBTeW50aFV0aWxzLnN5bnRoZXNpemUoc3RhY2spLnRlbXBsYXRlO1xuXG4gICAgdGVzdC5kZWVwRXF1YWwodGVtcGxhdGUuUGFyYW1ldGVycy5JbWFnZUltYWdlTmFtZTVFNjg0MzUzLCB7XG4gICAgICBUeXBlOiAnU3RyaW5nJyxcbiAgICAgIERlc2NyaXB0aW9uOiAnRUNSIHJlcG9zaXRvcnkgbmFtZSBhbmQgdGFnIGFzc2V0IFwiSW1hZ2VcIidcbiAgICB9KTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICd3aXRoIGJ1aWxkIGFyZ3MnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IGFzc2V0ID0gbmV3IERvY2tlckltYWdlQXNzZXQoc3RhY2ssICdJbWFnZScsIHtcbiAgICAgIGRpcmVjdG9yeTogcGF0aC5qb2luKF9fZGlybmFtZSwgJ2RlbW8taW1hZ2UnKSxcbiAgICAgIGJ1aWxkQXJnczoge1xuICAgICAgICBhOiAnYidcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIFRIRU5cbiAgICBjb25zdCBhc3NldE1ldGFkYXRhID0gYXNzZXQubm9kZS5tZXRhZGF0YS5maW5kKCh7IHR5cGUgfSkgPT4gdHlwZSA9PT0gJ2F3czpjZGs6YXNzZXQnKTtcbiAgICB0ZXN0LmRlZXBFcXVhbChhc3NldE1ldGFkYXRhICYmIGFzc2V0TWV0YWRhdGEuZGF0YS5idWlsZEFyZ3MsIHsgYTogJ2InIH0pO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdhc3NldC5yZXBvc2l0b3J5LmdyYW50UHVsbCBjYW4gYmUgdXNlZCB0byBncmFudCBhIHByaW5jaXBhbCBwZXJtaXNzaW9ucyB0byB1c2UgdGhlIGltYWdlJyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgICBjb25zdCB1c2VyID0gbmV3IGlhbS5Vc2VyKHN0YWNrLCAnTXlVc2VyJyk7XG4gICAgY29uc3QgYXNzZXQgPSBuZXcgRG9ja2VySW1hZ2VBc3NldChzdGFjaywgJ0ltYWdlJywge1xuICAgICAgZGlyZWN0b3J5OiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnZGVtby1pbWFnZScpXG4gICAgfSk7XG5cbiAgICAvLyBXSEVOXG4gICAgYXNzZXQucmVwb3NpdG9yeS5ncmFudFB1bGwodXNlcik7XG5cbiAgICAvLyBUSEVOXG4gICAgZXhwZWN0KHN0YWNrKS50byhoYXZlUmVzb3VyY2UoJ0FXUzo6SUFNOjpQb2xpY3knLCB7XG4gICAgICBQb2xpY3lEb2N1bWVudDoge1xuICAgICAgICBcIlN0YXRlbWVudFwiOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgXCJBY3Rpb25cIjogW1xuICAgICAgICAgICAgICBcImVjcjpCYXRjaENoZWNrTGF5ZXJBdmFpbGFiaWxpdHlcIixcbiAgICAgICAgICAgICAgXCJlY3I6R2V0RG93bmxvYWRVcmxGb3JMYXllclwiLFxuICAgICAgICAgICAgICBcImVjcjpCYXRjaEdldEltYWdlXCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBcIkVmZmVjdFwiOiBcIkFsbG93XCIsXG4gICAgICAgICAgICBcIlJlc291cmNlXCI6IHtcbiAgICAgICAgICAgICAgXCJGbjo6Sm9pblwiOiBbXG4gICAgICAgICAgICAgICAgXCJcIixcbiAgICAgICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAgICBcImFybjpcIixcbiAgICAgICAgICAgICAgICAgIHsgXCJSZWZcIjogXCJBV1M6OlBhcnRpdGlvblwiIH0sXG4gICAgICAgICAgICAgICAgICBcIjplY3I6XCIsXG4gICAgICAgICAgICAgICAgICB7IFwiUmVmXCI6IFwiQVdTOjpSZWdpb25cIiB9LFxuICAgICAgICAgICAgICAgICAgXCI6XCIsXG4gICAgICAgICAgICAgICAgICB7IFwiUmVmXCI6IFwiQVdTOjpBY2NvdW50SWRcIiB9LFxuICAgICAgICAgICAgICAgICAgXCI6cmVwb3NpdG9yeS9cIixcbiAgICAgICAgICAgICAgICAgIHsgXCJGbjo6R2V0QXR0XCI6IFsgXCJJbWFnZUFkb3B0UmVwb3NpdG9yeUUxRTg0RTM1XCIsIFwiUmVwb3NpdG9yeU5hbWVcIiBdIH1cbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIFwiQWN0aW9uXCI6IFwiZWNyOkdldEF1dGhvcml6YXRpb25Ub2tlblwiLFxuICAgICAgICAgICAgXCJFZmZlY3RcIjogXCJBbGxvd1wiLFxuICAgICAgICAgICAgXCJSZXNvdXJjZVwiOiBcIipcIlxuICAgICAgICAgIH1cbiAgICAgICAgXSxcbiAgICAgICAgXCJWZXJzaW9uXCI6IFwiMjAxMi0xMC0xN1wiXG4gICAgICB9LFxuICAgICAgXCJQb2xpY3lOYW1lXCI6IFwiTXlVc2VyRGVmYXVsdFBvbGljeTdCODk3NDI2XCIsXG4gICAgICBcIlVzZXJzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwiUmVmXCI6IFwiTXlVc2VyREM0NTAyOEJcIlxuICAgICAgICB9XG4gICAgICBdXG4gICAgfSkpO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ2Fzc2V0LnJlcG9zaXRvcnkuYWRkVG9SZXNvdXJjZVBvbGljeSBjYW4gYmUgdXNlZCB0byBtb2RpZnkgdGhlIEVDUiByZXNvdXJjZSBwb2xpY3kgdmlhIHRoZSBhZG9wdGlvbiBjdXN0b20gcmVzb3VyY2UnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICAgIGNvbnN0IGFzc2V0ID0gbmV3IERvY2tlckltYWdlQXNzZXQoc3RhY2ssICdJbWFnZScsIHtcbiAgICAgIGRpcmVjdG9yeTogcGF0aC5qb2luKF9fZGlybmFtZSwgJ2RlbW8taW1hZ2UnKVxuICAgIH0pO1xuXG4gICAgLy8gV0hFTlxuICAgIGFzc2V0LnJlcG9zaXRvcnkuYWRkVG9SZXNvdXJjZVBvbGljeShuZXcgaWFtLlBvbGljeVN0YXRlbWVudCgpXG4gICAgICAuYWRkQWN0aW9uKCdCT09NJylcbiAgICAgIC5hZGRQcmluY2lwYWwobmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCd0ZXN0LnNlcnZpY2UnKSkpO1xuXG4gICAgLy8gVEhFTlxuICAgIGV4cGVjdChzdGFjaykudG8oaGF2ZVJlc291cmNlKCdDdXN0b206OkVDUkFkb3B0ZWRSZXBvc2l0b3J5Jywge1xuICAgICAgXCJSZXBvc2l0b3J5TmFtZVwiOiB7XG4gICAgICAgIFwiRm46OlNlbGVjdFwiOiBbIDAsIHsgXCJGbjo6U3BsaXRcIjogWyBcIkBzaGEyNTY6XCIsIHsgXCJSZWZcIjogXCJJbWFnZUltYWdlTmFtZTVFNjg0MzUzXCIgfSBdIH0gXVxuICAgICAgfSxcbiAgICAgIFwiUG9saWN5RG9jdW1lbnRcIjoge1xuICAgICAgICBcIlN0YXRlbWVudFwiOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgXCJBY3Rpb25cIjogXCJCT09NXCIsXG4gICAgICAgICAgICBcIkVmZmVjdFwiOiBcIkFsbG93XCIsXG4gICAgICAgICAgICBcIlByaW5jaXBhbFwiOiB7XG4gICAgICAgICAgICAgIFwiU2VydmljZVwiOiBcInRlc3Quc2VydmljZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICBdLFxuICAgICAgICBcIlZlcnNpb25cIjogXCIyMDEyLTEwLTE3XCJcbiAgICAgIH1cbiAgICB9KSk7XG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnZmFpbHMgaWYgdGhlIGRpcmVjdG9yeSBkb2VzIG5vdCBleGlzdCcodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgICAvLyBUSEVOXG4gICAgdGVzdC50aHJvd3MoKCkgPT4ge1xuICAgICAgbmV3IERvY2tlckltYWdlQXNzZXQoc3RhY2ssICdNeUFzc2V0Jywge1xuICAgICAgICBkaXJlY3Rvcnk6IGAvZG9lcy9ub3QvZXhpc3QvJHtNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiA5OTk5KX1gXG4gICAgICB9KTtcbiAgICB9LCAvQ2Fubm90IGZpbmQgaW1hZ2UgZGlyZWN0b3J5IGF0Lyk7XG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ2ZhaWxzIGlmIHRoZSBkaXJlY3RvcnkgZG9lcyBub3QgY29udGFpbiBhIERvY2tlcmZpbGUnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gICAgLy8gVEhFTlxuICAgIHRlc3QudGhyb3dzKCgpID0+IHtcbiAgICAgIG5ldyBEb2NrZXJJbWFnZUFzc2V0KHN0YWNrLCAnQXNzZXQnLCB7XG4gICAgICAgIGRpcmVjdG9yeTogX19kaXJuYW1lXG4gICAgICB9KTtcbiAgICB9LCAvTm8gJ0RvY2tlcmZpbGUnIGZvdW5kIGluLyk7XG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ2RvY2tlciBkaXJlY3RvcnkgaXMgc3RhZ2VkIGlmIGFzc2V0IHN0YWdpbmcgaXMgZW5hYmxlZCcodGVzdDogVGVzdCkge1xuICAgIGNvbnN0IGFwcCA9IG5ldyBjZGsuQXBwKCk7XG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKGFwcCwgJ3N0YWNrJyk7XG5cbiAgICBuZXcgRG9ja2VySW1hZ2VBc3NldChzdGFjaywgJ015QXNzZXQnLCB7XG4gICAgICBkaXJlY3Rvcnk6IHBhdGguam9pbihfX2Rpcm5hbWUsICdkZW1vLWltYWdlJylcbiAgICB9KTtcblxuICAgIGNvbnN0IHNlc3Npb24gPSBhcHAuc3ludGgoKTtcblxuICAgIHRlc3Qub2soZnMuZXhpc3RzU3luYyhwYXRoLmpvaW4oc2Vzc2lvbi5kaXJlY3RvcnksICdhc3NldC4xYTE3YTE0MTUwNWFjNjkxNDQ5MzFmZTI2M2QxMzBmNDYxMjI1MWNhYTRiYmJkYWY2OGE0NGVkMGY0MDU0MzljL0RvY2tlcmZpbGUnKSkpO1xuICAgIHRlc3Qub2soZnMuZXhpc3RzU3luYyhwYXRoLmpvaW4oc2Vzc2lvbi5kaXJlY3RvcnksICdhc3NldC4xYTE3YTE0MTUwNWFjNjkxNDQ5MzFmZTI2M2QxMzBmNDYxMjI1MWNhYTRiYmJkYWY2OGE0NGVkMGY0MDU0MzljL2luZGV4LnB5JykpKTtcbiAgICB0ZXN0LmRvbmUoKTtcbiAgfVxufTtcbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/assets-docker/tsconfig.json b/packages/@aws-cdk/assets-docker/tsconfig.json new file mode 100644 index 0000000000000..df4fbecba7374 --- /dev/null +++ b/packages/@aws-cdk/assets-docker/tsconfig.json @@ -0,0 +1,72 @@ +{ + "compilerOptions": { + "alwaysStrict": true, + "charset": "utf8", + "declaration": true, + "experimentalDecorators": true, + "inlineSourceMap": true, + "inlineSources": true, + "lib": [ + "es2016", + "es2017.object", + "es2017.string" + ], + "module": "CommonJS", + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": false, + "stripInternal": true, + "target": "ES2018", + "composite": true + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "node_modules" + ], + "references": [ + { + "path": "../assets" + }, + { + "path": "../aws-cloudformation" + }, + { + "path": "../aws-ecr" + }, + { + "path": "../aws-iam" + }, + { + "path": "../aws-lambda" + }, + { + "path": "../aws-s3" + }, + { + "path": "../cdk" + }, + { + "path": "../cx-api" + }, + { + "path": "../assert" + }, + { + "path": "../../../tools/cdk-build-tools" + }, + { + "path": "../../../tools/pkglint" + } + ], + "_generated_by_jsii_": "Generated by jsii - safe to delete, and ideally should be in .gitignore" +} diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index 5db6f1d39d076..38d544f5a1010 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -190,8 +190,7 @@ of the constants such as `WindowsBuildImage.WIN_SERVER_CORE_2016_BASE` or Alternatively, you can specify a custom image using one of the static methods on `XxxBuildImage`: -* Use `.fromDockerHub(image)` to reference an image publicly available in Docker - Hub. +* Use `.fromDockerRegistry(image[, secretsManagerCredential])` to reference an image in any public or private Docker registry. * Use `.fromEcrRepository(repo[, tag])` to reference an image available in an ECR repository. * Use `.fromAsset(directory)` to use an image created from a @@ -205,6 +204,10 @@ The following example shows how to define an image from an ECR repository: [ECR example](./test/integ.ecr.lit.ts) +The following example shows how to define an image from a private docker registry: + +[Docker Registry example](./test/integ.docker-registry.lit.ts) + ## Events CodeBuild projects can be used either as a source for events or be triggered diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index 2bc55fcd51d28..88d092fd2b8df 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -5,7 +5,8 @@ import { DockerImageAsset, DockerImageAssetProps } from '@aws-cdk/aws-ecr-assets import events = require('@aws-cdk/aws-events'); import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); -import { Aws, CfnResource, Construct, Duration, IResource, Lazy, PhysicalName, Resource, ResourceIdentifiers, Stack } from '@aws-cdk/cdk'; +import secretsmanager = require('@aws-cdk/aws-secretsmanager'); +import { Aws, CfnResource, Construct, Duration, IResource, Lazy, PhysicalName, Resource, ResourceIdentifiers, Stack, Token } from '@aws-cdk/cdk'; import { IArtifacts } from './artifacts'; import { BuildSpec } from './build-spec'; import { Cache } from './cache'; @@ -780,6 +781,18 @@ export class Project extends ProjectBase { }); } + private attachEcrPermission() { + this.addToRolePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: [ + 'ecr:GetAutheticationToken', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage', + 'ecr:BatchCheckLayerAvailability' + ] + })); + } + private renderEnvironment(env: BuildEnvironment = {}, projectVars: { [name: string]: BuildEnvironmentVariable } = {}): CfnProject.EnvironmentProperty { const vars: { [name: string]: BuildEnvironmentVariable } = {}; @@ -797,6 +810,10 @@ export class Project extends ProjectBase { const hasEnvironmentVars = Object.keys(vars).length > 0; + if (isECRImage(this.buildImage.imageId)) { + this.attachEcrPermission(); + } + const errors = this.buildImage.validate(env); if (errors.length > 0) { throw new Error("Invalid CodeBuild environment: " + errors.join('\n')); @@ -805,6 +822,12 @@ export class Project extends ProjectBase { return { type: this.buildImage.type, image: this.buildImage.imageId, + imagePullCredentialsType: this.buildImage.imagePullCredentialsType, + registryCredential: this.buildImage.secretsManagerCredential ? + { + credentialProvider: 'SECRETS_MANAGER', + credential: this.buildImage.secretsManagerCredential.secretArn + } : undefined, privilegedMode: env.privileged || false, computeType: env.computeType || this.buildImage.defaultComputeType, environmentVariables: !hasEnvironmentVars ? undefined : Object.keys(vars).map(name => ({ @@ -929,6 +952,11 @@ export enum ComputeType { LARGE = 'BUILD_GENERAL1_LARGE' } +export enum ImagePullCredentialsType { + CodeBuild = 'CODEBUILD', + ServiceRole = 'SERVICE_ROLE' +} + export interface BuildEnvironment { /** * The image used for the builds. @@ -987,6 +1015,16 @@ export interface IBuildImage { */ readonly defaultComputeType: ComputeType; + /** + * The type of credentials AWS CodeBuild uses to pull images in your build. + */ + readonly imagePullCredentialsType?: ImagePullCredentialsType; + + /** + * The credentials for access to a private registry. + */ + readonly secretsManagerCredential?: secretsmanager.ISecret; + /** * Allows the image a chance to validate whether the passed configuration is correct. * @@ -1007,7 +1045,7 @@ export interface IBuildImage { * * You can also specify a custom image using one of the static methods: * - * - LinuxBuildImage.fromDockerHub(image) + * - LinuxBuildImage.fromDockerRegistry(image[, secretsManagerCredential]) * - LinuxBuildImage.fromEcrRepository(repo[, tag]) * - LinuxBuildImage.fromAsset(parent, id, props) * @@ -1051,8 +1089,8 @@ export class LinuxBuildImage implements IBuildImage { /** * @returns a Linux build image from a Docker Hub image. */ - public static fromDockerHub(name: string): LinuxBuildImage { - return new LinuxBuildImage(name); + public static fromDockerRegistry(name: string, secretsManagerCredential?: secretsmanager.ISecret): LinuxBuildImage { + return new LinuxBuildImage(name, ImagePullCredentialsType.ServiceRole, secretsManagerCredential); } /** @@ -1067,9 +1105,7 @@ export class LinuxBuildImage implements IBuildImage { * @param tag Image tag (default "latest") */ public static fromEcrRepository(repository: ecr.IRepository, tag: string = 'latest'): LinuxBuildImage { - const image = new LinuxBuildImage(repository.repositoryUriForTag(tag)); - repository.addToResourcePolicy(ecrAccessForCodeBuildService()); - return image; + return new LinuxBuildImage(repository.repositoryUriForTag(tag), ImagePullCredentialsType.ServiceRole); } /** @@ -1077,19 +1113,16 @@ export class LinuxBuildImage implements IBuildImage { */ public static fromAsset(scope: Construct, id: string, props: DockerImageAssetProps): LinuxBuildImage { const asset = new DockerImageAsset(scope, id, props); - const image = new LinuxBuildImage(asset.imageUri); - - // allow this codebuild to pull this image (CodeBuild doesn't use a role, so - // we can't use `asset.grantUseImage()`. - asset.repository.addToResourcePolicy(ecrAccessForCodeBuildService()); - - return image; + return new LinuxBuildImage(asset.imageUri, ImagePullCredentialsType.ServiceRole); } public readonly type = 'LINUX_CONTAINER'; public readonly defaultComputeType = ComputeType.SMALL; - private constructor(public readonly imageId: string) { + private constructor( + public readonly imageId: string, + public readonly imagePullCredentialsType?: ImagePullCredentialsType, + public readonly secretsManagerCredential?: secretsmanager.ISecret) { } public validate(_: BuildEnvironment): string[] { @@ -1132,7 +1165,7 @@ export class LinuxBuildImage implements IBuildImage { * * You can also specify a custom image using one of the static methods: * - * - WindowsBuildImage.fromDockerHub(image) + * - WindowsBuildImage.fromDockerRegistry(image[, secretsManagerCredential]) * - WindowsBuildImage.fromEcrRepository(repo[, tag]) * - WindowsBuildImage.fromAsset(parent, id, props) * @@ -1144,8 +1177,8 @@ export class WindowsBuildImage implements IBuildImage { /** * @returns a Windows build image from a Docker Hub image. */ - public static fromDockerHub(name: string): WindowsBuildImage { - return new WindowsBuildImage(name); + public static fromDockerRegistry(name: string, secretsManagerCredential?: secretsmanager.ISecret): WindowsBuildImage { + return new WindowsBuildImage(name, ImagePullCredentialsType.ServiceRole, secretsManagerCredential); } /** @@ -1160,9 +1193,7 @@ export class WindowsBuildImage implements IBuildImage { * @param tag Image tag (default "latest") */ public static fromEcrRepository(repository: ecr.IRepository, tag: string = 'latest'): WindowsBuildImage { - const image = new WindowsBuildImage(repository.repositoryUriForTag(tag)); - repository.addToResourcePolicy(ecrAccessForCodeBuildService()); - return image; + return new WindowsBuildImage(repository.repositoryUriForTag(tag), ImagePullCredentialsType.ServiceRole); } /** @@ -1170,18 +1201,15 @@ export class WindowsBuildImage implements IBuildImage { */ public static fromAsset(scope: Construct, id: string, props: DockerImageAssetProps): WindowsBuildImage { const asset = new DockerImageAsset(scope, id, props); - const image = new WindowsBuildImage(asset.imageUri); - - // allow this codebuild to pull this image (CodeBuild doesn't use a role, so - // we can't use `asset.grantUseImage()`. - asset.repository.addToResourcePolicy(ecrAccessForCodeBuildService()); - - return image; + return new WindowsBuildImage(asset.imageUri, ImagePullCredentialsType.ServiceRole); } public readonly type = 'WINDOWS_CONTAINER'; public readonly defaultComputeType = ComputeType.MEDIUM; - private constructor(public readonly imageId: string) { + private constructor( + public readonly imageId: string, + public readonly imagePullCredentialsType?: ImagePullCredentialsType, + public readonly secretsManagerCredential?: secretsmanager.ISecret) { } public validate(buildEnvironment: BuildEnvironment): string[] { @@ -1244,11 +1272,9 @@ export enum BuildEnvironmentVariableType { PARAMETER_STORE = 'PARAMETER_STORE' } -function ecrAccessForCodeBuildService(): iam.PolicyStatement { - const s = new iam.PolicyStatement({ - principals: [new iam.ServicePrincipal('codebuild.amazonaws.com')], - actions: ['ecr:GetDownloadUrlForLayer', 'ecr:BatchGetImage', 'ecr:BatchCheckLayerAvailability'], - }); - s.sid = 'CodeBuild'; - return s; +function isECRImage(imageUri: string) { + if (!Token.isUnresolved(imageUri)) { + return /^(.+).dkr.ecr.(.+).amazonaws.com[.]{0,1}[a-z]{0,3}\/([^:]+):?.*$/.test(imageUri); + } + return false; } diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 141e0620d4750..7802eee3c9800 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -88,6 +88,7 @@ "@aws-cdk/aws-kms": "^0.35.0", "@aws-cdk/aws-s3": "^0.35.0", "@aws-cdk/aws-s3-assets": "^0.35.0", + "@aws-cdk/aws-secretsmanager": "^0.35.0", "@aws-cdk/cdk": "^0.35.0" }, "homepage": "https://github.com/awslabs/aws-cdk", @@ -103,6 +104,7 @@ "@aws-cdk/aws-kms": "^0.35.0", "@aws-cdk/aws-s3": "^0.35.0", "@aws-cdk/aws-s3-assets": "^0.35.0", + "@aws-cdk/aws-secretsmanager": "^0.35.0", "@aws-cdk/cdk": "^0.35.0" }, "engines": { diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.docker-asset.lit.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.docker-asset.lit.expected.json index d4b6b0e10e84b..32ead4e776695 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.docker-asset.lit.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.docker-asset.lit.expected.json @@ -39,33 +39,6 @@ ] } ] - }, - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage", - "ecr:BatchCheckLayerAvailability" - ], - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "codebuild.", - { - "Ref": "AWS::URLSuffix" - } - ] - ] - } - }, - "Sid": "CodeBuild" - } - ], - "Version": "2012-10-17" } }, "DependsOn": [ @@ -439,6 +412,7 @@ ] ] }, + "ImagePullCredentialsType": "SERVICE_ROLE", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.expected.json new file mode 100644 index 0000000000000..b8cd00a66ffb2 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.expected.json @@ -0,0 +1,148 @@ +{ + "Resources": { + "MyProjectRole9BBE5233": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "codebuild.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "MyProjectRoleDefaultPolicyB19B7C29": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "MyProject39F7B0AE" + } + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "MyProject39F7B0AE" + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyProjectRoleDefaultPolicyB19B7C29", + "Roles": [ + { + "Ref": "MyProjectRole9BBE5233" + } + ] + } + }, + "MyProject39F7B0AE": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "NO_ARTIFACTS" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "my-registry/my-repo", + "ImagePullCredentialsType": "SERVICE_ROLE", + "PrivilegedMode": false, + "RegistryCredential": { + "Credential": { + "Fn::Join": [ + "", + [ + "arn:aws:secretsmanager:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":secret:my-secrets-123456" + ] + ] + }, + "CredentialProvider": "SECRETS_MANAGER" + }, + "Type": "LINUX_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "MyProjectRole9BBE5233", + "Arn" + ] + }, + "Source": { + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"ls\"\n ]\n }\n }\n}", + "Type": "NO_SOURCE" + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.ts b/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.ts new file mode 100644 index 0000000000000..c82ab1394a04d --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.ts @@ -0,0 +1,34 @@ +import secretsmanager = require('@aws-cdk/aws-secretsmanager'); +import cdk = require('@aws-cdk/cdk'); +import codebuild = require('../lib'); + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const secrets = secretsmanager.Secret.fromSecretArn(this, "MySecrets", + `arn:aws:secretsmanager:${this.region}:${this.account}:secret:my-secrets-123456`); + + new codebuild.Project(this, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: "0.2", + phases: { + build: { + commands: [ 'ls' ] + } + } + }), + /// !show + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry("my-registry/my-repo", secrets) + } + /// !hide + }); + } +} + +const app = new cdk.App(); + +new TestStack(app, 'test-codebuild-docker-asset'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.ecr.lit.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.ecr.lit.expected.json index 5bac318649a12..b7899d62a391b 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.ecr.lit.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.ecr.lit.expected.json @@ -1,37 +1,8 @@ { "Resources": { "MyRepoF4F48043": { - "DeletionPolicy": "Retain", "Type": "AWS::ECR::Repository", - "Properties": { - "RepositoryPolicyText": { - "Statement": [ - { - "Action": [ - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage", - "ecr:BatchCheckLayerAvailability" - ], - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "codebuild.", - { - "Ref": "AWS::URLSuffix" - } - ] - ] - } - }, - "Sid": "CodeBuild" - } - ], - "Version": "2012-10-17" - } - } + "DeletionPolicy": "Retain" }, "MyProjectRole9BBE5233": { "Type": "AWS::IAM::Role", @@ -186,6 +157,7 @@ ] ] }, + "ImagePullCredentialsType": "SERVICE_ROLE", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" },