diff --git a/packages/aws-cdk/lib/api/toolkit-info.ts b/packages/aws-cdk/lib/api/toolkit-info.ts index 726d34ae16596..b18d5477039a3 100644 --- a/packages/aws-cdk/lib/api/toolkit-info.ts +++ b/packages/aws-cdk/lib/api/toolkit-info.ts @@ -143,6 +143,14 @@ export class ToolkitInfo { lifecyclePolicyText: JSON.stringify(DEFAULT_REPO_LIFECYCLE) }).promise(); + // Configure image scanning on push (helps in identifying software vulnerabilities, no additional charge) + await ecr.putImageScanningConfiguration({ + repositoryName, + imageScanningConfiguration: { + scanOnPush: true + } + }).promise(); + return { repositoryUri: repository.repositoryUri!, repositoryName @@ -244,7 +252,7 @@ function getOutputValue(stack: aws.CloudFormation.Stack, output: string): string return result; } -const DEFAULT_REPO_LIFECYCLE = { +export const DEFAULT_REPO_LIFECYCLE = { rules: [ { rulePriority: 100, diff --git a/packages/aws-cdk/test/test.docker.ts b/packages/aws-cdk/test/test.docker.ts index b187f859a4346..9d877dfa0d619 100644 --- a/packages/aws-cdk/test/test.docker.ts +++ b/packages/aws-cdk/test/test.docker.ts @@ -1,7 +1,7 @@ import cxapi = require('@aws-cdk/cx-api'); import { Test } from 'nodeunit'; import sinon = require('sinon'); -import { ToolkitInfo } from '../lib'; +import { DEFAULT_REPO_LIFECYCLE, ToolkitInfo } from '../lib'; import { prepareContainerAsset } from '../lib/docker'; import os = require('../lib/os'); import { MockSDK } from './util/mock-sdk'; @@ -102,6 +102,77 @@ export = { test.done(); }, + async 'configures lifecycle policy and image scanning'(test: Test) { + // GIVEN + let putLifecyclePolicyParams; + let putImageScanningConfigurationParams; + + const sdk = new MockSDK(); + sdk.stubEcr({ + describeRepositories() { + return { repositories: [] }; + }, + + createRepository() { + return { + repository: { + repositoryUri: 'uri' + } + }; + }, + + putLifecyclePolicy(params) { + putLifecyclePolicyParams = params; + return {}; + }, + + putImageScanningConfiguration(params) { + putImageScanningConfigurationParams = params; + + // Stop the test so that we don't actually docker build + throw new Error('STOPTEST'); + } + }); + + const toolkit = new ToolkitInfo({ + sdk, + bucketName: 'BUCKET_NAME', + bucketEndpoint: 'BUCKET_ENDPOINT', + environment: { name: 'env', account: '1234', region: 'abc' } + }); + + // WHEN + const asset: cxapi.ContainerImageAssetMetadataEntry = { + id: 'assetId', + imageNameParameter: 'MyParameter', + packaging: 'container-image', + path: '/foo', + repositoryName: 'some-name', + sourceHash: '0123456789abcdef', + }; + + try { + await prepareContainerAsset('.', asset, toolkit, false); + } catch (e) { + if (!/STOPTEST/.test(e.toString())) { throw e; } + } + + // THEN + test.deepEqual(putLifecyclePolicyParams, { + repositoryName: 'some-name', + lifecyclePolicyText: JSON.stringify(DEFAULT_REPO_LIFECYCLE) + }); + + test.deepEqual(putImageScanningConfigurationParams, { + repositoryName: 'some-name', + imageScanningConfiguration: { + scanOnPush: true + } + }); + + test.done(); + }, + async 'passes the correct target to docker build'(test: Test) { // GIVEN const toolkit = new ToolkitInfo({