codebuild-notifier

Reports status of AWS CodeBuild CI jobs to Slack.

Infrastructure Requirements

Slack App or Bot in your workspace

Notifications will be sent as Slack Direct Messages to users from the default Slack bot in your workspace (e.g. @slackbot)

  • Go to https://api.slack.com/apps
  • Create a New App, e.g. App Name: CodeBuild Notifier
  • Under Add features and functionality select "Permissions" and grant these scopes:
    • chat:write:bot
    • users:read
    • users:read.email
  • Click Install App To Workspace and store the OAuth token generated in a new secret in AWS Secrets Manager (see below)

Optional Add a Bot User to your app - instead of the default Slack bot, messages will come from a user with a name you choose, e.g. CodeBuildBot

  • Under Features / Bot Users, click Add a Bot User
  • Select a name and display name; the always show as online option does not matter
  • After adding the Bot User, re-install the app to your workspace
  • A new OAuth token will be generated specific to the Bot User. Store this in AWS Secrets Manager instead of the App token.

DynamoDB table for build history

  • expected to be named 'codebuild-history', but can be configured
  • the following definition:
  AttributeDefinitions [
    { AttributeName: 'commit_hash', AttributeType: 'S' },
    { AttributeName: 'source_id', AttributeType: 'S' },
    { AttributeName: 'version_key', AttributeType: 'S' }
  ]
  GlobalSecondaryIndexes [
    {
      IndexName: 'commit_hash_index',
      KeySchema: [
        { AttributeName: 'commit_hash', KeyType: 'HASH' },
        { AttributeName: 'version_key', KeyType: 'RANGE' }
      ],
      Projection: { ProjectionType: 'ALL' }
    }
  ]
  KeySchema [
    { AttributeName: 'source_id', KeyType: 'HASH' },
    { AttributeName: 'version_key', KeyType: 'RANGE' }
  ]

Secret in AWS Secrets Manager

  • expected to be named 'slack/codebuild', but can be configured
  • contents should be: json { "token": "xoxo-your-slack-app-token" }

Optional DynamoDB table for Slack aliases

Slack message recipients are located by extracting the email address of the author/commiter of the git commit triggering the build, then searching for users with that email address within the Slack workspace.

Users might sign commits with a different email address than they used to register with Slack. Even if their git config has a matching address, merges and commits made via the github web interface may use the primary email address for the user's github account, or [email protected].

To ensure delivery in these cases, a second DynamoDb table can be created and configured to do a second lookup if the original lookup fails.

  • suggested table name: 'codebuild-slack-aliases', but can be configured
  • by default, the table name is unspecified, meaning no second lookup will be performed
  • the email address for which the original lookup fails (the commit signature address) should be stored in index field alternate_email
  • the user's Slack email address should be stored in a string field named workspace_email
  • multiple items can be created with different values for alternate_email pointing to the same workspace_email value
  • the table should have the following definition: ruby AttributeDefinitions [ { AttributeName: 'alternate_email', AttributeType: 'S' } ] KeySchema [ { AttributeName: 'alternate_email', KeyType: 'HASH' } ]

IAM Service Role for CodeBuild projects

You will likely already have a service role granting CloudWatch access, to which you will want to add the following, substituing your region, account id, and if different, dynamo table name and secrets-manager secret name:

{
  "Action": [
    "dynamodb:BatchGetItem",
    "dynamodb:GetItem",
    "dynamodb:PutItem",
    "dynamodb:Query",
    "dynamodb:Scan",
    "dynamodb:UpdateItem"
  ],
  "Effect": "Allow",
  "Resource": [
    "arn:aws:dynamodb:<your-region>:<your-account-id>:table/codebuild-history",
    "arn:aws:dynamodb:<your-region>:<your-account-id>:table/codbuild-history/*",
    // if optional slack alias table is configured
    "arn:aws:dynamodb:<your-region>:<your-account-id>:table/codebuild-slack-aliases",
    "arn:aws:dynamodb:<your-region>:<your-account-id>:table/codbuild-slack-aliases/*"
  ]
},
{
  "Action": "secretsmanager:GetSecretValue",
  "Effect": "Allow",
  "Resource": [
    "arn:aws:secretsmanager:<your-region>:<your-account-id>:secret:slack/codebuild*"
  ]
}

Configuration

Installation

Pre-requisites

The base docker image used for your CodeBuild project must include ruby, or you must install it using the project's buildspec.yml file. Any ruby from 2.3.x to 2.5.x will work.

Using buildspec

Add to the install: phase of your buildspec.yml

phases:
  install:
    commands:
      - gem install codebuild-notifier

Using custom Docker image

Add to your Dockerfile

RUN gem install codebuild-notifier

Usage

Add to the post_build: phase of your buildspec.yml file

phases:
  post_build:
    commands:
      - update-build-status

Configuration

ENV vars

ENV vars can either be set in Dockerfile e.g.

ENV CBN_SLACK_ADMIN_USERNAMES scooby,shaggy

Or in buildspec.yml

env:
  variables:
    CBN_SLACK_ADMIN_USERNAMES: 'fred,velma'

command-line

In buildspec.yml

phases:
  post_build:
    commands:
      - update-build-status --slack-admin-usernames="fred,velma"

Options

ENV var command-line Default value Notes
CBN_ADDITIONAL_CHANNEL --additional-channel not set If whitelist branches are set, status notifications for these branches can be sent to this channel, as well as direct messages to the author/committer of the commit triggering the build.
CBN_AWS_REGION --region value of AWS_REGION env var in CodeBuild container If for some reason the dynamo table and secrets-manager live in a different region than where CodeBuild is executing, you can specify that region.
CBN_DEFAULT_NOTIFY_STRATEGY --default-notify-strategy fail_or_status_change Determines when notifications will be sent. 'status_change' sends notifications for the first build in a PR or whitelisted branch, thereafter if a build in that PR/branch has a different status to the previous build. 'every_build' sends a notification regardless of status. 'fail_or_status_change', the default value, will send if the status changes, but will also send notifications of every failure, regardless of previous status.
CBN_DYNAMO_TABLE --dynamo-table codebuild-history This table must be created and permissions granted to it as described in Infrastructure Requirements
CBN_OVERRIDE_NOTIFY_STRATEGY --override-notify-strategy not set Allows overriding default notify strategy. Specify a branch and strategy for that branch, with a colon separator. Valid strategies are: status_change, every_build, fail_or_status_change Specify multiple branch strategies delimited by comma. e.g. 'master:every_build,jira-15650:status_change'
CBN_SLACK_ADMIN_USERNAMES --slack-admin-usernames not set If no Slack user can be found in your workspace with the email address of the author or committer of a commit, a message will be sent to the Slack usernames specified.
Separate multiple values with commas, with no spaces.
e.g. fred,velma
CBN_SLACK_ALIAS_TABLE --slack-alias-table not set If no Slack user can be found in your workspace with the email address of the author or committer of a commit, this table will be queried to find the Slack workspace email matching the failed address.
CBN_SLACK_SECRET_NAME --slack-secret-name slack/codebuild The name of a secret in AWS Secrets Manager with the app or bot auth token.
CBN_WHITELIST_BRANCHES --whitelist-branches master Normally statuses will be stored and notifications sent only for builds triggered by commits to branches with open Pull Requests. However, it can be useful to get notifications for all commits to certain branches, regardless of Pull Request status.
Separate multiple values with commas, without spaces.
e.g. 'master,nightly,jira-50012'