Skip to content

Define the Quality Gates and Continuous Integration

In this section, we will guide you through setting up quality gates and continuous integration (CI) in your workflow. You’ll learn how to configure checkpoints to ensure your code meets standards and how to automate integration and testing using CI tools.

The setup of quality gates and CI may vary depending on the technologies and tools used in the project, but at a high level, they follow these key steps: code style checking or static code analysis (linting), vulnerability scanning for dependencies and the codebase, project building, and executing various tests.

We will mainly edit the package.json file in this section. Open that file and follow the steps below.

Build & Test Steps

The build and test steps are already included in this workshop’s setup. Let’s test them.

Step 1: Run the build command to transpile the TypeScript code to JavaScript.

npm run build

CDK JSON Configuration

Congratulations! You’ve successfully compiled the project. Your code is now transpiled from TypeScript to JavaScript.

Step 2: Run the test command to execute the Unit tests.

npm run test

Well done! You’ve completed running the unit tests. These checks ensure that your code behaves as expected.

Unifying Code Style and Static Code Checks

Step 3: Install ESLint

For NPM projects, it’s common to use eslint for code styling and static code analysis. To install eslint, run the following command:

npm install --save-dev eslint @eslint/core @eslint/js @types/eslint__js typescript typescript-eslint @stylistic/eslint-plugin

Step 4: Create the ESLint Configuration File

Create a file called eslint.config.mjs in the project root with the following content:

import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import stylistic from '@stylistic/eslint-plugin';

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.strict,
  ...tseslint.configs.stylistic,
  stylistic.configs.customize({
    indent: 2,
    quotes: 'single',
    semi: true,
  }),
  {
    ignores: [
      'node_modules/**/*',
      'cdk.out/**/*',
      '**/*.js',
      '**/*.d.ts',
    ],
  },
  {
    rules: {
      '@stylistic/eol-last': ['off'], // workshop code removes the tailing spaces, that is why this rule disabled
      '@typescript-eslint/no-useless-constructor': ['warn'], // AWS CDK example code has useless constructor
    },
  },
);

Great job! You’ve set up your ESLint configuration, which will help maintain code quality and uniformity across the project.

Step 5: Add the lint script to package.json

Open the package.json file and insert a new script called lint like this: "lint": "eslint ."

Your package.json should look like:

{
  "name": "cdk-cicd-example",
  "version": "0.1.0",
  "scripts": {
    "build": "tsc",
    "test": "jest",
    "lint": "eslint .",
    "cdk": "cdk"
  }
}

Step 6: Run the lint script to test it.

npm run lint

Congratulations! You’ve successfully run the linter. Your code is now checked for style and potential errors.

Security Scan of Third-Party Dependencies and Codebase

Step 7: Add a Third-Party dependency audit step

Edit the package.json and include the audit step for dependencies:

"audit:deps": "cdk-cicd check-dependencies --npm --python"

This command will analyze both NPM and Python dependencies and report any known vulnerabilities.

Awesome! You’ve added an important step to scan your third-party dependencies for vulnerabilities.

Step 8: Add a security scan step for the codebase

Include the security scan for the source code in package.json:

"audit:security-scan": "cdk-cicd security-scan --bandit --semgrep --shellcheck"

This will run scanners (Bandit, Semgrep, Shellcheck) on the codebase to detect security risks.

Well done! You’ve set up the security scan to keep your code safe from common vulnerabilities.

Ensure package.json Integrity

Step 9: Validate package.json

Edit the package.json and include the following validation script:

"validate": "cdk-cicd validate"

To run the validation:

npm run validate

This may fail on the first execution since validation hasn’t been executed before. To fix it, run:

npm run validate -- --fix
Repeat this process anytime you modify the `package.json` file.

Fantastic! You’ve ensured that your configuration is now validated, keeping your project secure and consistent.

Verifying Third-Party Licenses

Step 10: Audit licenses

Edit package.json to include a license audit step:

"audit:license": "cdk-cicd license"

To run the license audit:

npm run audit:license

It may fail the first time because it verifies the existence of the NOTICE file in your repository. Fix it by running:

npm run audit:license -- --fix

This will generate the NOTICE file and the OSS_License_Summary.csv summarizing the used license types in your project.

Repeat this process anytime you modify the package.json, requirement.txt, and / or Pipfile.

Congrats! You’ve completed the license audit, ensuring all third-party dependencies are legally valid and accounted for.

Concurrent Execution of Audits

Running multiple security checks can take time, so it's beneficial to parallelize them.

Step 10: Edit the package.json to include:

"audit": "concurrently 'npm:audit:*'"

Install the dependency:

npm install --save-dev concurrently

Run the audit command:

npm run audit

If the audit fails due to package.json modifications, run:

npm run audit:license -- --fix
npm run validate -- --fix

Then, re-run:

npm run audit

Amazing! You’ve successfully parallelized your audit tasks, saving time while ensuring your code remains safe and compliant.

Summary

By the end of this section, we have defined all the necessary steps for a high-quality, robust CI pipeline for an AWS CDK-based project. These include:

  • validate: Ensures our configuration isn’t tampered with.
  • build: Ensures our code compiles correctly.
  • test: Ensures tests are executed.
  • lint: Ensures code style and quality.
  • audit: Ensures dependencies are vulnerability-free and legally valid, and the codebase doesn't introduce security risks.
Show Solution

The package.json file should look like this:

{
  "name": "cdk-cicd-example",
  "version": "0.1.0",
  "bin": {
    "cdk-cicd-example": "bin/cdk-cicd-example.js"
  },
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "lint": "eslint .",
    "audit": "concurrently 'npm:audit:*'",
    "audit:deps": "cdk-cicd check-dependencies --npm --python",
    "audit:security-scan": "cdk-cicd security-scan --bandit --semgrep --shellcheck",
    "audit:license": "cdk-cicd license",
    "validate": "cdk-cicd validate",
    "cdk": "cdk"
  },
  "devDependencies": {
    "@eslint/js": "^9.10.0",
    "@stylistic/eslint-plugin": "^2.8.0",
    "@types/eslint__js": "^8.42.3",
    "@types/jest": "^29.5.12",
    "@types/node": "22.5.4",
    "aws-cdk": "2.158.0",
    "concurrently": "^9.0.1",
    "eslint": "^9.10.0",
    "jest": "^29.7.0",
    "ts-jest": "^29.2.5",
    "ts-node": "^10.9.2",
    "typescript": "~5.6.2",
    "typescript-eslint": "^8.6.0"
  },
  "dependencies": {
    "@cdklabs/cdk-cicd-wrapper": "^0.2.12",
    "@cdklabs/cdk-cicd-wrapper-cli": "^0.2.10",
    "aws-cdk-lib": "2.158.0",
    "constructs": "^10.0.0",
    "source-map-support": "^0.5.21"
  }
}

✓ Congratulations!
You’ve completed setting up all your quality gates and continuous integration steps. You now have a strong foundation for building, testing, and securing your AWS CDK project!

Click Next to continue to the next section.

Next