in packages/@aws-c2a/cdk-pipelines-step/lib/private/change-analysis-check.ts [72:202]
constructor(scope: Construct, id: string, props: ChangeAnalysisCheckProps) {
super(scope, id);
Tags.of(props.codePipeline).add('CHANGE_ANALYSIS', 'ALLOW_APPROVE', {
includeResourceTypes: ['AWS::CodePipeline::Pipeline'],
});
const { preApproveLambda, invokeLambda } = new PreApproveLambda(this, 'C2APreApproveLambda', {
pipelineTag: 'CHANGE_ANALYSIS',
});
this.preApproveLambda = preApproveLambda;
const { accessKeySecret, bucket, putObject, signObject} = new WebAppBucket(this, 'C2ABucket', {
autoDeleteObjects: props.autoDeleteObjects,
});
this.bucket = bucket;
// eslint-disable-next-line @typescript-eslint/no-require-imports,@typescript-eslint/no-var-requires
const myVersion = require(path.resolve(
__dirname,
'..',
'..',
'package.json',
)).version;
const message = [
'An upcoming change would violate configured rules settings in $PIPELINE_NAME.',
'Review and approve the changes in CodePipeline to proceed with the deployment.',
'',
'Review the changes in CodeBuild:',
'',
'$LINK',
'',
'Approve the changes in CodePipeline (stage $STAGE_NAME, action $ACTION_NAME):',
'',
'$PIPELINE_LINK',
];
const publishNotification =
'aws sns publish' +
' --topic-arn $NOTIFICATION_ARN' +
' --subject "$NOTIFICATION_SUBJECT"' +
` --message "${message.join('\n')}"`;
const diff =
'aws-c2a diff' +
` --app "assembly-${props.codePipeline.stack.stackName}-$STAGE_NAME/"` +
' ${BROADENING_PERMISSIONS:+--broadening-permissions}' +
' ${RULE_SET:+--rules-path "$RULE_SET"}' +
' --fail';
this.c2aDiffProject = new codebuild.Project(this, 'CDKChangeAnalysis', {
environmentVariables: {
DOWNLOAD_USER_KEY: {
type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER,
value: `${accessKeySecret.secretArn}:AWS_ACCESS_KEY_ID`,
},
DOWNLOAD_USER_SECRET: {
type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER,
value: `${accessKeySecret.secretArn}:AWS_SECRET_ACCESS_KEY`,
},
},
buildSpec: codebuild.BuildSpec.fromObject({
version: 0.2,
phases: {
build: {
commands: [
'set -e',
// We have to pull this down separately because the synth stage
// value of the asset hash might be different than the deploy stage
// hash value
'[ -z "${RULE_SET}" ] || aws s3 cp s3://$BUCKET/$RULE_SET $RULE_SET',
`npm install -g aws-c2a@${myVersion}`,
// $CODEBUILD_INITIATOR will always be Code Pipeline and in the form of:
// "codepipeline/example-pipeline-name-Xxx"
'export PIPELINE_NAME="$(node -pe \'`${process.env.CODEBUILD_INITIATOR}`.split("/")[1]\')"',
'payload="$(node -pe \'JSON.stringify({ "PipelineName": process.env.PIPELINE_NAME, "StageName": process.env.STAGE_NAME, "ActionName": process.env.ACTION_NAME })\' )"',
// ARN: "arn:aws:codebuild:$region:$account_id:build/$project_name:$project_execution_id$"
'ARN=$CODEBUILD_BUILD_ARN',
'REGION="$(node -pe \'`${process.env.ARN}`.split(":")[3]\')"',
'ACCOUNT_ID="$(node -pe \'`${process.env.ARN}`.split(":")[4]\')"',
'PROJECT_NAME="$(node -pe \'`${process.env.ARN}`.split(":")[5].split("/")[1]\')"',
'PROJECT_ID="$(node -pe \'`${process.env.ARN}`.split(":")[6]\')"',
'export PIPELINE_LINK="https://$REGION.console.aws.amazon.com/codesuite/codepipeline/pipelines/$PIPELINE_NAME/view?region=$REGION"',
// Run invoke only if cdk diff passes (returns exit code 0)
// 0 -> true, 1 -> false
ifElse({
condition: diff,
thenStatements: [
invokeLambda,
'export MESSAGE="No changes that violate rules detected."',
],
elseStatements: [
'aws-c2a html --report report.json',
putObject,
`export LINK=$(${signObject})`,
`[ -z "\${NOTIFICATION_ARN}" ] || ${publishNotification}`,
'export MESSAGE="Deployment would make security-impacting changes. Click the link below to inspect them, then click Approve if all changes are expected."',
],
}),
],
},
},
env: {
'exported-variables': [
'LINK',
'MESSAGE',
],
},
}),
});
// this is needed to check the status the stacks when doing `cdk diff`
this.c2aDiffProject.addToRolePolicy(new iam.PolicyStatement({
actions: ['sts:AssumeRole'],
resources: ['*'],
conditions: {
'ForAnyValue:StringEquals': {
'iam:ResourceTag/aws-cdk:bootstrap-role': ['deploy'],
},
},
}));
this.c2aDiffProject.addToRolePolicy(new iam.PolicyStatement({
actions: ['cloudformation:GetTemplate', 'cloudformation:DescribeStackResources', 'cloudformation:DescribeStacks'],
resources: ['*'],
}));
this.preApproveLambda.grantInvoke(this.c2aDiffProject);
this.bucket.grantWrite(this.c2aDiffProject);
}