Simple Steps to Include CDK Diffs in GitHub PRs

Simple Steps to Include CDK Diffs in GitHub PRs

ยท

6 min read

Hey, everyone! If you've been using AWS, chances are you've come across CDK and building cloud apps with it. As seamless as it is to deploy apps using CDK, it is equally important to monitor changes in infrastructure code and prevent issues.

This guide is here to make your life a bit easier by showing you how to include the CDK diff directly in your GitHub PR.

Let's start by understanding the CDK first.

A Brief Overview of CDK (Cloud Development Kit)

The Cloud Development Kit (CDK) enables developers to define, build, and deploy cloud infrastructure as code using supported programming languages. A CDK app consists of one or more Stacks where each stack defines AWS resources it uses, such as Lambda function, EC2 instance or SNS. This CDK app is usually written in TypeScript, JavaScript, Python, Java, C# or Go.

A stack is simply a collection of AWS resources in the form of constructs managed as a single unit. You instantiate constructs within a stack to declare them to AWS and connect them using well-defined interfaces.

Here's an example of using a construct in AWS CDK to create an Amazon S3 bucket with public read access:

import { Stack, StackProps, Construct } from '@aws-cdk/core';
import { Bucket } from '@aws-cdk/aws-s3';

export class MyS3BucketStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const bucket = new Bucket(this, 'MyS3Bucket', {
      publicReadAccess: true,
    });
  }
}

Since a construct is a reusable piece of code that encapsulates AWS resource creation and configuration logic, we can say that these constructs are the building blocks of a CDK app. Please pay close attention to this point, as it will be crucial in understanding why it is important to assess the CDK differences effectively.

Importance of CDK Diffs in GitHub PRs (Pull Requests)

As we just learned, a CDK app enables seamless building and deployment of cloud infrastructure as code. Since we define the resources used in an app as constructs, they can be employed to analyze the differences in resource allocation when changes occur.

These changes can be harmful if overlooked, leading to poor resource allocation, inconsistencies, and fatal crashes.

At times, it may not be apparent that changes could result in the deletion and recreation of a resource. For instance, in the case of a database, this could have disastrous consequences. That's why monitoring whenever there is a change in infrastructure code is essential.

The integration of CDK diffs in GitHub Pull Requests (PRs) makes it much easier for developers to review and analyze changes in the infrastructure code. This helps streamline the development process and ensure efficient cloud infrastructure management.

A CDK diff highlights any modifications, additions, or deletions made to the codebase in a concise format. Since this information is available directly within the pull request, it can be leveraged to understand the proposed changes better, assess their impact, and make informed decisions. This, in turn, helps to minimize the risk of errors and maintain the stability and security of the cloud infrastructure, ultimately leading to a more reliable and robust system.

I hope I've managed to convince you why having the CDK diff available in each pull request is crucial.

Now, let's proceed to learn how to incorporate them.

Creating GitHub Workflow to Include CDK Diff as a PR Comment

Since we need to add a comment with the CDK difference, we will use GitHub workflow to run a job whenever there is a new pull request. Create a yaml file inside .github/workflows and follow the steps below:

Feel free to click here if you want to skip the explanation.

Step 1: Add a name for the job and make sure it runs on pull requests only

// .github/workflows/cdk-diff-share.yaml
name: Run CDK difference

on:
  pull_request:
    branches: ['main']

Step 2: Define a Job and Set the Environment, Permissions and Machine it Runs On

jobs:
  build:
    name: Run CDK diff
    environment: prod
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: write
      pull-requests: write

Make sure you have contents and pull-requests access so that the job can post the comment.

Step 3: Define Steps to Checkout the Repo and Install Dependencies

steps:
      - name: Checkout repo
        uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.ref }}
          repository: ${{ github.event.pull_request.head.repo.full_name }}
      - name: Install pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 7.27.1
      - name: Setup Node and Cache
        uses: actions/setup-node@v3
        with:
          node-version: 16
          cache: pnpm
      - name: Install dependencies
        run: pnpm install --prefer-offline

We are also setting up the cache to speed up the consecutive runs.

Step 4: Configure AWS credentials

We need to be authenticated to access the AWS console; let's set up the AWS credentials using an IAM role.

- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v1-node16
  with:
      role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE }}
      aws-region: <region-of-your-choice>

Note: Always use GitHub secrets to store any credentials.

Step 5: Run CDK sync

Run the CDK synth command to generate a CloudFormation stack. We are using aws-cdk to run CDK commands.

- name: CDK synth
  run: pnpm cdk synth
  env:
     SKIP_SANDBOX: true

Step 6: Run CDK diff

Run the CDK diff command to compare the current stack with the deployed stack. Since we need this log in the next step to post a comment, we will also save this in a log file, say output.log.

Once we generate the log file, we can parse it and make it available as GITHUB_OUTPUT.

- name: Run AWS CDK diff
  run: pnpm cdk diff --app "./cdk.out/assembly-ProdStage" 2>&1 2>&1 | tee output.log
   env:
      SKIP_SANDBOX: true
- name: Echo output log
  id: output_log
  run: |
     echo "data<<EOF" >> $GITHUB_OUTPUT
     echo "$(cat output.log)" >> $GITHUB_OUTPUT
     echo "EOF" >> $GITHUB_OUTPUT

Here, 2>&1 2>&1 | tee output.log redirects both stdout and stderr to output.log file and also prints them on the console

Step 7: Post the comment

We are using mshick/add-pr-comment@v2 to post a log on the GitHub pull request. We will add a markdown wrapper around the log to make it appear visually appealing.

- name: Post diff in comment
  uses: mshick/add-pr-comment@v2
  with:
    message-id: cdk-diff
    message: |
      #### CDK Diff for ProdStage
      <details>
         <summary>Show diff</summary>
         ` ` `bash
         ${{ steps.output_log.outputs.data }}
         ` ` `
      </details>

That's we are done. Here's how the log should appear:

Here's the complete script:

name: Run CDK difference

on:
  pull_request:
    branches: ['main']

jobs:
  build:
    name: Run CDK diff
    environment: prod
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: write
      pull-requests: write
    steps:
      - name: Checkout repo
        uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.ref }}
          repository: ${{ github.event.pull_request.head.repo.full_name }}
      - name: Install pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 7.27.1
      - name: Setup Node and Cache
        uses: actions/setup-node@v3
        with:
          node-version: 16
          cache: pnpm
      - name: Install dependencies
        run: pnpm install --prefer-offline
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE }}
          aws-region: <your-region-here>
      - name: CDK synth
        run: pnpm cdk synth
        env:
          SKIP_SANDBOX: true
      - name: Run AWS CDK diff
        run: pnpm cdk diff --app "./cdk.out/assembly-ProdStage" 2>&1 2>&1 | tee output.log
        env:
          SKIP_SANDBOX: true
      - name: Save output
        id: output_log
        run: |
          echo "data<<EOF" >> $GITHUB_OUTPUT
          echo "$(cat output.log)" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT
      - name: Post diff in comment
        uses: mshick/add-pr-comment@v2
        with:
          message-id: cdk-diff
          message: |
            #### CDK Diff for ProdStage
            <details>
              <summary>Show diff</summary>
              ` ` `bash
              ${{ steps.output_log.outputs.data }}
              ` ` `
            </details>

Please remove the space between backticks `.

Conclusion

CDK diff in GitHub PRs helps us review and analyze changes in infrastructure code, minimizing the risk of errors and maintaining stability and security. CDK diffs highlight modifications, additions, or deletions in the codebase, enabling a better understanding of proposed changes and informed decision-making.

We learned how to utilize cdk diff it to see changes in the intended deployment and post them as a comment on our GitHub PRs.

Do let us know if this article was helpful in the comments.