Static Code Analysis for Node.js and TypeScript Project using SonarQube

What is SonarQube?

SonarQube is an open-source quality management platform, dedicated to continuously analyze and measure technical quality, from project portfolio to method.

Code Quality and Code Security | SonarQube

image

Basic of SonarQube

  • SonarQube (formerly just “Sonar”) is a server-based system. Of course, you can install it on your local machine (the hardware requirements are minimal). But it is a central server with a database.

  • SonarQube is an open-source platform developed by SonarSource for continuous inspection of code quality. Sonar does static code analysis, which provides a detailed report of bugs, code smells, vulnerabilities, code duplications.

  • SonarQube also highlights the complex areas of code that are less covered by unit tests.

Basic Highlights

Release Quality Code: Catch tricky bugs to prevent undefined behaviour from impacting end-users.

Application Security: Fix vulnerabilities that compromise your app, and learn AppSec along the way with Security Hotspots.

Technical Debt: Make sure your codebase is clean and maintainable, to increase developer velocity!

Setup Sonarqube on the local machine

We are going to use a bitnami-docker-sonarqube image to set up Sonarqube on our local machine.

For more details, you can check a bitnami-docker-sonarqube GitHub repository.

bitnami/bitnami-docker-sonarqube

Run the application using Docker Compose

Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application's services.

Use the following command to get the docker-composeconfiguration on your local machine.

$ curl -sSL https://raw.githubusercontent.com/bitnami/bitnami-docker-sonarqube/master/docker-compose.yml > docker-compose.yml
$ docker-compose up -d

bitnami imagebitnami image

Or else you can create docker-compose.yml file and use the following configuration to run Sonarqube using docker-compose up -d command.

version: '2'

services:
  postgresql:
    image: docker.io/bitnami/postgresql:10
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
    volumes:
      - 'postgresql_data:/bitnami/postgresql'
  sonarqube:
    image: docker.io/bitnami/sonarqube:8
    ports:
      - '80:9000'
    environment:
      - POSTGRESQL_HOST=postgresql
      - POSTGRESQL_ROOT_USER=postgres
      - POSTGRESQL_CLIENT_CREATE_DATABASE_NAME=bitnami_sonarqube
      - POSTGRESQL_CLIENT_CREATE_DATABASE_USERNAME=bn_sonarqube
      - POSTGRESQL_CLIENT_CREATE_DATABASE_PASSWORD=bitnami1234
      - SONARQUBE_DATABASE_NAME=bitnami_sonarqube
      - SONARQUBE_DATABASE_USER=bn_sonarqube
      - SONARQUBE_DATABASE_PASSWORD=bitnami1234
    volumes:
      - sonarqube_data:/bitnami
volumes:
  sonarqube_data:
    driver: local
  postgresql_data:
    driver: local

Run the application using Docker ComposeRun the application using Docker Compose

Access your application at http://127.0.0.1 and use the below credentials to login into the application.

**Username** - **admin**
**Password** - **bitnami**

http://127.0.0.1http://127.0.0.1

Analyzing a Project

  • Click the Create new project button.

  • Give your project a **Project key **and a Display name and click the Set Up button.

  • Under Provide a token, select Generate a token. Give your token a name, click the Generate button, and click Continue.

  • Copy the generated token and paste it into our .env file corresponding to the variable SONARQUBE_TOKEN.

  • Example : SONARQUBE_TOKEN=generated-token

  • Make sure to set environment variables in .env file.

    SONARQUBE_URL=http://127.0.0.1 SONARQUBE_PROJECTKEY=sonarqube-node-tpescript-demo SONARQUBE_TOKEN=43b915a482ba1dce4b36c215718e56e37ad9e910

Configuring SonarQube over our Node and TypeScript project

First, you need to clone the Skeleton for Node.js applications written in TypeScript

santoshshinde2012/node-boilerplate

// clone the repository
git clone [https://github.com/santoshshinde2012/node-boilerplate.git](https://github.com/santoshshinde2012/node-boilerplate.git)

// install the npm modules
npm install

Use sonarqube-scanner npm module to run SonarQube/SonarCloud analyses.

To add code analysis to your build files, simply add the package to your project dev dependencies:

npm install --save-dev sonarqube-scanner

SonarQube Configuration File

At the root of the project, we are going to create sonar-scanner.ts a file that contains the source code for the SonarQube scanner configuration.

import * as scanner from 'sonarqube-scanner'
import { config as configDotenv } from 'dotenv';

// config the environment
configDotenv();

// The URL of the SonarQube server. Defaults to http://localhost:9000
const serverUrl = process.env.SONARQUBE_URL;

// The token used to connect to the SonarQube/SonarCloud server. Empty by default.
const token = process.env.SONARQUBE_TOKEN;

// projectKey must be unique in a given SonarQube instance
const projectKey = process.env.SONARQUBE_PROJECTKEY

// options Map (optional) Used to pass extra parameters for the analysis.
// See the [official documentation](https://docs.sonarqube.org/latest/analysis/analysis-parameters/) for more details.
const options = {

  'sonar.projectKey': projectKey,

  // projectName - defaults to project key
  'sonar.projectName': 'node-typescript-boilerplate',

  // Path is relative to the sonar-project.properties file. Defaults to .
  'sonar.sources': 'src',

  // source language
  'sonar.language': 'ts',

  'sonar.javascript.lcov.reportPaths' : 'coverage/lcov.info',

  // Encoding of the source code. Default is default system encoding
  'sonar.sourceEncoding': 'UTF-8'
};

// parameters for sonarqube-scanner
const params = {
  serverUrl,
  token,
  options
}

const sonarScanner = async () => {

  console.log(serverUrl);

  if (!serverUrl) {
    console.log('SonarQube url not set. Nothing to do...');
    return;
  }

  //  Function Callback (the execution of the analysis is asynchronous).
  const callback  = (result) => {
    console.log('Sonarqube scanner result:', result);
  }

  scanner(params, callback);
}

sonarScanner()
  .catch(err => console.error('Error during sonar scan', err));

How to fix “parserOptions.project” has been set for @typescript-eslint/parser ?

Simply instruct eslint to ignore them by adding the ignorePatterns option to your .eslintrc: "ignorePatterns": ["sonar.js"]

{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "airbnb/base",
    "plugin:@typescript-eslint/recommended",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:import/typescript",
    "prettier"
  ],
  "parserOptions": {
    "ecmaVersion": 2018,
    "project": "./tsconfig.json"
  },
  "ignorePatterns": ["sonar-scanner.ts"], // This line should be add in configuration
  "plugins": ["prettier"],
  "rules": {}
}

Example — https://raw.githubusercontent.com/santoshshinde2012/sonarqube-node-tpescript-demo/master/.eslintrc

// source code with all files needed for the demo
git clone [https://github.com/santoshshinde2012/sonarqube-node-tpescript-demo.git](https://github.com/santoshshinde2012/sonarqube-node-tpescript-demo.git)

How to Run SonarQube Scanner

Please add the below script in package.json to run SonarQube Scanner, make sure you already installed ts-node locally or globally.

"sonar": "ts-node sonar-scanner.ts"

Start the SonarQube Scanner by using the command on terminal

npm run sonar

Output after running npm run sonar

➜  node-boilerplate git:(master) ✗ npm run sonar

> sonarqube-node-tpescript-demo@1.0.0 sonar
> ts-node sonar-scanner.ts

http://127.0.0.1:80
[23:30:35] Starting analysis...
[23:30:35] Getting info from "package.json" file
[23:30:35] Checking if executable exists: /Users/macbook/.sonar/native-sonar-scanner/sonar-scanner-4.5.0.2216-macosx/bin/sonar-scanner
[23:30:35] Platform binaries for SonarScanner found. Using it.
INFO: Scanner configuration file: /Users/macbook/.sonar/native-sonar-scanner/sonar-scanner-4.5.0.2216-macosx/conf/sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: SonarScanner 4.5.0.2216
INFO: Java 11.0.3 AdoptOpenJDK (64-bit)
INFO: Mac OS X 10.16 x86_64
INFO: User cache: /Users/macbook/.sonar/cache
INFO: Scanner configuration file: /Users/macbook/.sonar/native-sonar-scanner/sonar-scanner-4.5.0.2216-macosx/conf/sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: Analyzing on SonarQube server 8.9.1
INFO: Default locale: "en_IN", source code encoding: "UTF-8"
INFO: Load global settings
INFO: Load global settings (done) | time=150ms
INFO: Server id: FD2E0B99-AXqmE06gm3W0APi1RPSm
INFO: User cache: /Users/macbook/.sonar/cache
INFO: Load/download plugins
INFO: Load plugins index
INFO: Load plugins index (done) | time=71ms
INFO: Load/download plugins (done) | time=4641ms
INFO: Process project properties
INFO: Process project properties (done) | time=6ms
INFO: Execute project builders
INFO: Execute project builders (done) | time=3ms
INFO: Project key: sonarqube-node-tpescript-demo
INFO: Base dir: /Users/macbook/Documents/workspace/node-boilerplate
INFO: Working dir: /Users/macbook/Documents/workspace/node-boilerplate/.scannerwork
INFO: Load project settings for component key: 'sonarqube-node-tpescript-demo'
INFO: Load project settings for component key: 'sonarqube-node-tpescript-demo' (done) | time=101ms
INFO: Load quality profiles
INFO: Load quality profiles (done) | time=100ms
INFO: Load active rules
INFO: Load active rules (done) | time=4058ms
INFO: Indexing files...
INFO: Project configuration:
INFO:   Excluded sources: node_modules/**, bower_components/**, jspm_packages/**, typings/**, lib-cov/**
INFO: 12 files indexed
INFO: 0 files ignored because of inclusion/exclusion patterns
INFO: 0 files ignored because of scm ignore settings
INFO: Quality profile for ts: Sonar way
INFO: ------------- Run sensors on module node-typescript-boilerplate
INFO: Load metrics repository
INFO: Load metrics repository (done) | time=81ms
INFO: Sensor CSS Rules [cssfamily]
INFO: No CSS, PHP, HTML or VueJS files are found in the project. CSS analysis is skipped.
INFO: Sensor CSS Rules [cssfamily] (done) | time=1ms
INFO: Sensor JaCoCo XML Report Importer [jacoco]
INFO: 'sonar.coverage.jacoco.xmlReportPaths' is not defined. Using default locations: target/site/jacoco/jacoco.xml,target/site/jacoco-it/jacoco.xml,build/reports/jacoco/test/jacocoTestReport.xml
INFO: No report imported, no coverage information will be imported by JaCoCo XML Report Importer
INFO: Sensor JaCoCo XML Report Importer [jacoco] (done) | time=3ms
INFO: Sensor TypeScript analysis [javascript]
INFO: Found 1 tsconfig.json file(s): [/Users/macbook/Documents/workspace/node-boilerplate/tsconfig.json]
INFO: Analyzing 12 files using tsconfig: /Users/macbook/Documents/workspace/node-boilerplate/tsconfig.json
INFO: 12 source files to be analyzed
INFO: Load project repositories
INFO: Load project repositories (done) | time=105ms
INFO: 12/12 source files have been analyzed
INFO: Sensor TypeScript analysis [javascript] (done) | time=11441ms
INFO: Sensor JavaScript/TypeScript Coverage [javascript]
WARN: No coverage information will be saved because LCOV file cannot be found.
WARN: Provided LCOV file path: coverage/lcov.info. Seek file with path: /Users/macbook/Documents/workspace/node-boilerplate/coverage/lcov.info
WARN: No coverage information will be saved because all LCOV files cannot be found.
INFO: Sensor JavaScript/TypeScript Coverage [javascript] (done) | time=1ms
INFO: Sensor C# Project Type Information [csharp]
INFO: Sensor C# Project Type Information [csharp] (done) | time=1ms
INFO: Sensor C# Properties [csharp]
INFO: Sensor C# Properties [csharp] (done) | time=1ms
INFO: Sensor JavaXmlSensor [java]
INFO: Sensor JavaXmlSensor [java] (done) | time=1ms
INFO: Sensor HTML [web]
INFO: Sensor HTML [web] (done) | time=3ms
INFO: Sensor VB.NET Project Type Information [vbnet]
INFO: Sensor VB.NET Project Type Information [vbnet] (done) | time=1ms
INFO: Sensor VB.NET Properties [vbnet]
INFO: Sensor VB.NET Properties [vbnet] (done) | time=0ms
INFO: ------------- Run sensors on project
INFO: Sensor Zero Coverage Sensor
INFO: Sensor Zero Coverage Sensor (done) | time=13ms
INFO: SCM Publisher SCM provider for this project is: git
INFO: SCM Publisher 12 source files to be analyzed
INFO: SCM Publisher 0/12 source files have been analyzed (done) | time=66ms
WARN: Missing blame information for the following files:
WARN:   * src/server.ts
WARN:   * src/environments/environment.constant.ts
WARN:   * src/lib/logger.ts
WARN:   * src/abstractions/ApiResponses.ts
WARN:   * src/middleware/error-handler.ts
WARN:   * src/components/system-status/system-status.controller.ts
WARN:   * src/components/system-status/system-status.types.ts
WARN:   * src/routes.ts
WARN:   * src/environments/environment.ts
WARN:   * src/components/BaseApi.ts
WARN:   * src/abstractions/ApiError.ts
WARN:   * src/App.ts
WARN: This may lead to missing/broken features in SonarQube
INFO: CPD Executor 3 files had no CPD blocks
INFO: CPD Executor Calculating CPD for 9 files
INFO: CPD Executor CPD calculation finished (done) | time=13ms
INFO: Analysis report generated in 68ms, dir size=124 KB
INFO: Analysis report compressed in 51ms, zip size=35 KB
INFO: Analysis report uploaded in 159ms
INFO: ANALYSIS SUCCESSFUL, you can browse http://127.0.0.1/dashboard?id=sonarqube-node-tpescript-demo
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://127.0.0.1/api/ce/task?id=AXqmLdoG21WQGzQaFi7o
INFO: Analysis total time: 25.450 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 32.270s
INFO: Final Memory: 12M/50M
INFO: ------------------------------------------------------------------------
[23:31:08] Analysis finished.
Sonarqube scanner result: undefined
➜  node-boilerplate git:(master) ✗

Let's check the results on http://127.0.0.1/dashboard?id=sonarqube-node-tpescript-demo

ResultResult

Let's see the detailed list of problems pointed by SonarQube analysis on the 'Issues' tab.

IssuesIssues

References

Source code for SonarQube for Node JS and Typescript Project

santoshshinde2012/sonarqube-node-typescript-demo

bitnami/bitnami-docker-sonarqube

Try Out SonarQube

Enjoyed this article?

Share it with your network to help others discover it

Continue Learning

Discover more articles on similar topics