Charlie Thomas

Keeping your Node.js projects secure with CI/CD

A guide on how to setup security audits and outdated dependency alerts for your Node.js applications using automation.


Lots of times we as developers like to pretend that all the code we are writing is secure by nature. After all, who wants to admit that the product they are crafting is guaranteed to have vulnerabilities given enough time? At the same time, security practices often can work against the developer's overall tooling experience and agility, so we find ourselves in a never ending battle between practicality and crafting ethical and secure software. The bottom line is: security is a discipline that requires us as developers to change our processes at their core so that we can develop quickly and sleep soundly at night.

When in doubt, automate it!

The answer is obvious isn't it? Make the bots do it! Any time a development team is faced with a task that requires significant, recurring work the best approach is to start by asking, "How can I automate this task?".

Unfortunately, a bot isn't going to design secure applications for you (...not yet at least 😬 ), but what can it do for you? To answer this, lets look at what the npm CLI can do for us out of the box.

$ npm audit --audit-level=moderate
$ npm outdated

With these simple npm commands, we have a the basic building block we need to fail our build process when a security vulnerability is found in the dependency list and notify us when our packages are falling behind their recommended versions.

Block the build!

So let's take these CLI tools and put them to practice. For this guide, I will be using GitHub Actions to implement a very basic application of these to help get you bootstrapped.

The general idea is to create an automation job that will run on any pull request to master. First up, lets block the build upon a failing audit.

name: Run Checks

on:
  pull_request:
    branches: [ master ]

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup Node
        uses: actions/setup-node@v1
        with:
          node-version: '14.x'
      - name: CI Install
        run: npm ci
      - name: Audit
        run: npm audit --audit-level=moderate

This workflow will spin up and run the audit command discussed earlier, but to force your team to actually honor this check we need to change some of the configurations in GitHub as seen below:

Try and Keep Up!

Next, lets upgrade our previously defined workflow to include outdated notifications. The goal would be that this does not block incoming pull requests, but rather notifies the team about outdated dependencies via a slack web-hook. Alternatively, you could use something like Dependabot but we'll stick with actions just to demonstrate the basic concept.

name: Run Checks

on:
  pull_request:
    branches: [ master ]
  schedule:
    - cron: '0 17 * * 5' # every friday at 5 PM 😈

jobs:
  check_versions:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - run: npm ci
      - uses: MeilCli/npm-update-check-action@v4
        id: outdated
      - uses: 8398a7/action-slack@v2
        if: steps.outdated.outputs.has_npm_update != 'false'
        with:
          status: ${{ job.status }}
          text: ${{ steps.outdated.outputs.npm_update_text }}
          author_name: GitHub Actions
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Rather than rolling our own script that leverages npm outdated, we can use one of the many community maintained actions that are out there! In this example we will use npm-update-check-action. As you can see in the code snippet above, we simply need to pull in the action and pass its output to one of the many slack web-hook actions out there to notify the team if an outdated package is detected.

To improve upon this, some next steps you could experiment with are:

  • Opening a github issue to track the status of how the team chooses to handle the outdated package.
  • Implement Dependabot
  • Have the action comment if this action was triggered via PR.

In Summary

  • Security is a discipline that should effect the process of application development, packaging artifacts, and deploying.
  • Developers should strive for automated ways to hold their teams accountable to fixing outdated packages and security vulnerabilities.
  • With the npm CLI, we have many ways to solve vulnerability and outdated package auditing that we can leverage in our pipelines.

References