From 9b1f501dd60c182857d70670586e11eb912198f1 Mon Sep 17 00:00:00 2001 From: vinamra28 Date: Thu, 28 May 2020 14:50:11 +0530 Subject: [PATCH] Add SonarQube Task to catalog The following task can be used to do static analysis of the source code by taking SonarQube server URL as the input. Signed-off-by: vinamra28 --- sonarqube/README.md | 117 ++++++++++++++++++++ sonarqube/examples/pvc.yaml | 11 ++ sonarqube/examples/run.yaml | 50 +++++++++ sonarqube/examples/sonar-project.properties | 18 +++ sonarqube/sonarqube.yaml | 64 +++++++++++ 5 files changed, 260 insertions(+) create mode 100644 sonarqube/README.md create mode 100644 sonarqube/examples/pvc.yaml create mode 100644 sonarqube/examples/run.yaml create mode 100644 sonarqube/examples/sonar-project.properties create mode 100644 sonarqube/sonarqube.yaml diff --git a/sonarqube/README.md b/sonarqube/README.md new file mode 100644 index 00000000..fbb2acca --- /dev/null +++ b/sonarqube/README.md @@ -0,0 +1,117 @@ +# SonarQube + +SonarQube™ is the leading tool for continuously inspecting the Code Quality and Security™ of your codebases, all while empowering development teams. Analyze over 25 popular programming languages including C#, VB.Net, JavaScript, TypeScript and C++. It detects bugs, vulnerabilities and code smells across project branches and pull requests. + +The following task can be used to perform static analysis on the source code provided the SonarQube server is hosted. + +For creating your own `sonar-project.properties` please follow the guide [here](https://docs.sonarqube.org/latest/analysis/analysis-parameters/). Sample properties file can be found [here](./examples/sonar-project.properties) + +## Install the Task + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/v1beta1/sonarqube/sonarqube.yaml +``` + +## Pre-requisite + +Install the `git-clone` task from the catalog + +``` +https://raw.githubusercontent.com/tektoncd/catalog/v1beta1/git/git-clone.yaml +``` + +## Parameters + +- **SONAR_HOST_URL**: Host URL where the sonarqube server is running +- **SONAR_PROJECT_KEY**: Project's unique key + +> _Note_ : Parameters are provided in that case when we want to override the corresponding values in `sonar-project.properties` or there is no `sonar-project.properties` present for the project which needs to be analyzed + +## Workspaces + +- **source-dir**: `PersistentVolumeClaim`-type so that volume can be shared among git-clone and sonarqube task. Sample PVC can be found [here](./examples/pvc.yaml) +- **sonar-settings**: To mount the `sonar-project.properties` via the `ConfigMap`. (_Default_ : `emptyDir:{}`) + + To mount via the `ConfigMap`: + + ``` + kubectl create configmap sonar-properties --from-file="sonar-project.properties" + ``` + +## Running SonarQube Server locally using Docker + +1. Boot SonarQube + + ``` + docker run --name="sonarqube" -d sonarqube + ``` + +2. Get the IP address exposed by docker image to access sonarqube server + + ``` + docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' + ``` + +Sample IPAddress we will obtain using above command is like http://172.17.0.2:9000 + +## Usage + +1. `sonar-project.properties` present in Github Repository. For example :- following [repo](https://github.com/vinamra28/sonartest) contains the properties file and Sonar Host URL needs to be updated via the `params`. + The sample run for this scenario can be found [here](./examples/run.yaml) + +2. In case when no `sonar-project.properties` file is present then above two parameters are mandatory to create a `sonar-project.properties` file with the required fields or the file can be mounted via the `ConfigMap`. + +``` +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: sonarqube-pipeline +spec: + workspaces: + - name: shared-workspace + - name: sonar-settings + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/vinamra28/replace-tokens-plugin + - name: subdirectory + value: "" + - name: deleteExisting + value: "true" + - name: code-analysis + taskRef: + name: sonarqube-scanner + runAfter: + - fetch-repository + params: + - name: SONAR_HOST_URL + value: http://172.17.0.2:9000 + - name: SONAR_PROJECT_KEY + value: testapp + workspaces: + - name: source-dir + workspace: shared-workspace + - name: sonar-settings + workspace: sonar-settings +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: sonarqube-run +spec: + pipelineRef: + name: sonarqube-pipeline + workspaces: + - name: shared-workspace + persistentvolumeclaim: + claimName: sonar-source-pvc + - name: sonar-settings + emptyDir: {} +``` diff --git a/sonarqube/examples/pvc.yaml b/sonarqube/examples/pvc.yaml new file mode 100644 index 00000000..de396949 --- /dev/null +++ b/sonarqube/examples/pvc.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: sonar-source-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 500Mi diff --git a/sonarqube/examples/run.yaml b/sonarqube/examples/run.yaml new file mode 100644 index 00000000..c0bc3095 --- /dev/null +++ b/sonarqube/examples/run.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: sonarqube-pipeline +spec: + workspaces: + - name: shared-workspace + - name: sonar-settings + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/vinamra28/sonartest + - name: subdirectory + value: "" + - name: deleteExisting + value: "true" + - name: code-analysis + taskRef: + name: sonarqube-scanner + runAfter: + - fetch-repository + params: + - name: SONAR_HOST_URL + value: http://172.17.0.2:9000 + workspaces: + - name: source-dir + workspace: shared-workspace + - name: sonar-settings + workspace: sonar-settings +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: sonarqube-run +spec: + pipelineRef: + name: sonarqube-pipeline + workspaces: + - name: shared-workspace + persistentvolumeclaim: + claimName: sonar-source-pvc + - name: sonar-settings + emptyDir: {} diff --git a/sonarqube/examples/sonar-project.properties b/sonarqube/examples/sonar-project.properties new file mode 100644 index 00000000..5388a6a1 --- /dev/null +++ b/sonarqube/examples/sonar-project.properties @@ -0,0 +1,18 @@ +# required metdata +sonar.projectKey=node-test-app +sonar.projectVersion=1.0 +sonar.sourceEncoding=UTF-8 +sonar.host.url=http://172.17.0.2:9000 +# sonar.language=js +sonar.eslint.eslintconfigpath=app/eslintrc.json + +# path to srouce directories +sonar.sources=app +# sonar.tests=app/test/integration/api/ + +# excludes +sonar.exclusions=app/node_modules/*,app/coverage/lcov-report/*,app/test/integration/api/v1/*,app/middlewares/common-middleware.js + +# coverage reporting +sonar.javascript.lcov.reportPaths=app/coverage/lcov.info +# sonar.surefire.reportPaths=app/coverage/lcov-report \ No newline at end of file diff --git a/sonarqube/sonarqube.yaml b/sonarqube/sonarqube.yaml new file mode 100644 index 00000000..7f46f613 --- /dev/null +++ b/sonarqube/sonarqube.yaml @@ -0,0 +1,64 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: sonarqube-scanner +spec: + workspaces: + - name: source-dir + - name: sonar-settings + params: + - name: SONAR_HOST_URL + description: Host URL where the sonarqube server is running + default: "" + - name: SONAR_PROJECT_KEY + description: Project's unique key + default: "" + steps: + - name: sonar-properties-create + image: registry.access.redhat.com/ubi8/ubi-minimal:latest + workingDir: $(workspaces.source-dir.path) + script: | + #!/usr/bin/env bash + + replaceValues() { + filename=$1 + thekey=$2 + newvalue=$3 + + if ! grep -R "^[#]*\s*${thekey}=.*" $filename >/dev/null; then + echo "APPENDING because '${thekey}' not found" + echo "" >>$filename + echo "$thekey=$newvalue" >>$filename + else + echo "SETTING because '${thekey}' found already" + sed -ir "s|^[#]*\s*${thekey}=.*|$thekey=$newvalue|" $filename + fi + } + + if [[ -f $(workspaces.sonar-settings.path)/sonar-project.properties ]]; then + echo "using user provided sonar-project.properties file" + cp -R $(workspaces.sonar-settings.path)/sonar-project.properties $(workspaces.source-dir.path)/sonar-project.properties + fi + + if [[ -f $(workspaces.source-dir.path)/sonar-project.properties ]]; then + if [[ -n "$(params.SONAR_HOST_URL)" ]]; then + replaceValues $(workspaces.source-dir.path)/sonar-project.properties sonar.host.url $(params.SONAR_HOST_URL) + fi + if [[ -n "$(params.SONAR_PROJECT_KEY)" ]]; then + replaceValues $(workspaces.source-dir.path)/sonar-project.properties sonar.projectKey $(params.SONAR_PROJECT_KEY) + fi + else + touch sonar-project.properties + echo "sonar.projectKey=$(params.SONAR_PROJECT_KEY)" >> sonar-project.properties + echo "sonar.host.url=$(params.SONAR_HOST_URL)" >> sonar-project.properties + echo "sonar.sources=." >> sonar-project.properties + fi + + echo "---------------------------" + cat $(workspaces.source-dir.path)/sonar-project.properties + + - name: sonar-scan + image: sonarsource/sonar-scanner-cli + workingDir: $(workspaces.source-dir.path) + command: + - sonar-scanner