diff --git a/.gitignore b/.gitignore
index 90c1bc5ad02e6297d71a087737926200c7b55413..5e36a746cd6a5789567e212d45ab35d43827b611 100644
--- a/.gitignore
+++ b/.gitignore
@@ -68,3 +68,5 @@ secret
 /secrets/
 
 .project
+
+.scannerwork
diff --git a/Jenkinsfile b/Jenkinsfile
index e169f388e0bf9e0a389b6b58f6fcbc332871bfa2..13f260b0de4cca4a554d2b63f15ad42312f08b3a 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -51,6 +51,9 @@ pipeline {
           - mountPath: "/home/jenkins/.npm"
             name: "npm-cache"
             readOnly: false
+          - mountPath: "/home/jenkins/.sonar"
+            name: "sonar-cache"
+            readOnly: false
         - name: jnlp
           resources:
             requests:
@@ -74,6 +77,8 @@ pipeline {
           emptyDir: {}
         - name: npm-cache
           emptyDir: {}
+        - name: sonar-cache
+          emptyDir: {}
       '''
     }
   }
@@ -93,6 +98,7 @@ pipeline {
       """,
       returnStdout: true
     )
+    SONAR_HOST = 'https://sonarcloud.io'
   }
 
   options {
@@ -106,14 +112,33 @@ pipeline {
   }
 
   stages {
-    stage('Test sync scripts') {
+    stage('Run tests with Sonarcloud scan') {
+      when {
+        branch 'master'
+      }
+
       steps {
         container('buildcontainer') {
           readTrusted 'package.json'
-          
-          sh '''
-            npm ci --no-cache && npm run test
-          '''
+          sh 'npm ci --no-cache && npm run test'
+          withCredentials([string(credentialsId: 'sonarcloud-token-eclipsefdn-vc-tools', variable: 'SONAR_TOKEN')]) {
+              sh 'npm run sonar-scan'
+          }
+        }
+      }
+    }
+
+    stage('Run tests without Sonarcloud scan') {
+      when {
+        not {
+          branch 'master'
+        }
+      }
+
+      steps {
+        container('buildcontainer') {
+          readTrusted 'package.json'
+          sh 'npm ci --no-cache && npm run test'
         }
       }
     }
diff --git a/package-lock.json b/package-lock.json
index 225b12fe1a824d0570aaec32bab2bbabaf0a2db4..b867c9c110c2c82b763d8ac042f56fdf77bfe4d0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -45,6 +45,7 @@
         "faker": "^5.5.3",
         "jest": "^29.7.0",
         "sinon": "^10.0.0",
+        "sonarqube-scanner": "^3.4.0",
         "ts-jest": "^29.1.2"
       }
     },
@@ -2539,6 +2540,27 @@
         "node": ">=0.4.0"
       }
     },
+    "node_modules/adm-zip": {
+      "version": "0.5.12",
+      "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz",
+      "integrity": "sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -3266,6 +3288,15 @@
         "simple-swizzle": "^0.2.2"
       }
     },
+    "node_modules/color-support": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+      "dev": true,
+      "bin": {
+        "color-support": "bin.js"
+      }
+    },
     "node_modules/colorette": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
@@ -4279,6 +4310,18 @@
       "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==",
       "dev": true
     },
+    "node_modules/fancy-log": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-2.0.0.tgz",
+      "integrity": "sha512-9CzxZbACXMUXW13tS0tI8XsGGmxWzO2DmYrGuBJOJ8k8q2K7hwfJA5qHjuPPe8wtsco33YR9wc+Rlr5wYFvhSA==",
+      "dev": true,
+      "dependencies": {
+        "color-support": "^1.1.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -4749,6 +4792,19 @@
         "node": ">=10.19.0"
       }
     },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
+      "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/human-signals": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -6393,6 +6449,18 @@
         "node": ">=8"
       }
     },
+    "node_modules/jest-sonar-reporter": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/jest-sonar-reporter/-/jest-sonar-reporter-2.0.0.tgz",
+      "integrity": "sha512-ZervDCgEX5gdUbdtWsjdipLN3bKJwpxbvhkYNXTAYvAckCihobSLr9OT/IuyNIRT1EZMDDwR6DroWtrq+IL64w==",
+      "dev": true,
+      "dependencies": {
+        "xml": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
     "node_modules/jest-util": {
       "version": "29.7.0",
       "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
@@ -7132,6 +7200,18 @@
         "path-to-regexp": "^1.7.0"
       }
     },
+    "node_modules/node-downloader-helper": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmjs.org/node-downloader-helper/-/node-downloader-helper-2.1.9.tgz",
+      "integrity": "sha512-FSvAol2Z8UP191sZtsUZwHIN0eGoGue3uEXGdWIH5228e9KH1YHXT7fN8Oa33UGf+FbqGTQg3sJfrRGzmVCaJA==",
+      "dev": true,
+      "bin": {
+        "ndh": "bin/ndh"
+      },
+      "engines": {
+        "node": ">=14.18"
+      }
+    },
     "node_modules/node-fetch": {
       "version": "2.7.0",
       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
@@ -7923,6 +8003,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/shell-quote": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
+      "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/side-channel": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -8101,6 +8190,53 @@
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
       "dev": true
     },
+    "node_modules/slugify": {
+      "version": "1.6.6",
+      "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
+      "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/sonarqube-scanner": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/sonarqube-scanner/-/sonarqube-scanner-3.4.0.tgz",
+      "integrity": "sha512-2B/IgA2CkTg8GPKlkqxSPuWLlcEZcoRxWkcZYr47f8Ni1YOEbCS/EUl9/bn68sanZ0lee5adRPuQpGj0EiEW2A==",
+      "dev": true,
+      "dependencies": {
+        "adm-zip": "^0.5.10",
+        "fancy-log": "^2.0.0",
+        "https-proxy-agent": "^7.0.1",
+        "jest-sonar-reporter": "^2.0.0",
+        "mkdirp": "^3.0.1",
+        "node-downloader-helper": "^2.1.9",
+        "progress": "^2.0.3",
+        "shell-quote": "^1.8.1",
+        "slugify": "^1.6.6"
+      },
+      "bin": {
+        "sonar-scanner": "src/bin/sonar-scanner"
+      },
+      "engines": {
+        "node": ">= 16"
+      }
+    },
+    "node_modules/sonarqube-scanner/node_modules/mkdirp": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+      "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "dist/cjs/src/bin.js"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/source-map": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -8888,6 +9024,12 @@
       "resolved": "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz",
       "integrity": "sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw=="
     },
+    "node_modules/xml": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
+      "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==",
+      "dev": true
+    },
     "node_modules/xtend": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
diff --git a/package.json b/package.json
index 7db44e465c265dbdefb91116b52270402337360f..e2ed205193b64d365f4f9ba19d113d2a08c789c0 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
     "start": "node src/SyncCLI.js -c",
     "pretest": "eslint --ignore-path .gitignore .",
     "test": "jest --config=./jest.config.ts",
+    "sonar-scan": "node sonar-scanner.js",
     "lab-sync": "ts-node -v && ts-node src/scripts/gl/GitlabSync.ts",
     "lab-env": "ts-node -v && ts-node src/scripts/gl/TestEnvironment.ts",
     "import-backup": "node src/auto_backup/Import.js",
@@ -58,6 +59,7 @@
     "faker": "^5.5.3",
     "jest": "^29.7.0",
     "sinon": "^10.0.0",
+    "sonarqube-scanner": "^3.4.0",
     "ts-jest": "^29.1.2"
   }
 }
diff --git a/sonar-scanner.js b/sonar-scanner.js
new file mode 100644
index 0000000000000000000000000000000000000000..54a31e38fd8d39c6521d2a9c9bf08e7a40799580
--- /dev/null
+++ b/sonar-scanner.js
@@ -0,0 +1,28 @@
+/** *******************************************************************
+* Copyright (c) 2024 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+const scanner = require('sonarqube-scanner');
+
+// Holds all configs for scanning this project with SonarCloud and SonarQube
+scanner(
+  {
+    serverUrl: process.env.SONAR_HOST,
+    token: process.env.SONAR_TOKEN,
+    options: {
+      'sonar.projectName': 'Eclipse VC-Tools',
+      'sonar.organization': 'eclipse-foundation-it',
+      'sonar.projectKey': 'eclipsefdn-vc-tools',
+      'sonar.projectVersion': '1.0.0-BETA',
+      'sonar.sources': 'src',
+      'sonar.tests': 'test',
+      'sonar.javascript.lcov.reportPaths': './coverage/lcov.info'
+    },
+  },
+  () => process.exit(),
+);