diff --git a/.harness/JENKINS_INVENTORY.md b/.harness/JENKINS_INVENTORY.md new file mode 100644 index 00000000..bcf7a393 --- /dev/null +++ b/.harness/JENKINS_INVENTORY.md @@ -0,0 +1,58 @@ +# Jenkins Pipeline Stage Inventory (Springboot-BankApp) + +This note captures every stage in the existing Jenkins DevSecOps pipeline so the +Harness pipeline/templates in this directory can reproduce it 1:1. The Jenkins +files remain the source of truth until teams cut over; this is an **additive** +standardization, nothing is deleted. + +## Source files +- `Jenkinsfile` — CI job (`BankApp-CI`), uses `@Library('Shared')` from `vars/`. +- `GitOps/Jenkinsfile` — CD job (`BankApp-CD`), triggered by CI on success. +- `vars/*.groovy` — shared library step implementations (see mapping below). + +## CI pipeline (`Jenkinsfile`) + +| # | Jenkins stage | Shared-lib call (`vars/`) | Underlying command | Harness equivalent | +|---|---------------|---------------------------|--------------------|--------------------| +| 1 | Workspace cleanup | `cleanWs()` | Jenkins built-in | Implicit — Harness runs each stage on a fresh pod/workspace | +| 2 | Git: Code Checkout | `code_checkout(url, "DevOps")` | `git url:… branch:DevOps` | `cloneCodebase: true` + Harness code connector | +| 3 | Trivy: Filesystem scan | `trivy_scan()` | `trivy fs .` | `Run` step — Trivy fs (in security step group) | +| 4 | OWASP: Dependency check | `owasp_dependency()` | `dependencyCheck --scan ./` + publish `dependency-check-report.xml` | `Run` step — OWASP Dependency-Check (in security step group) | +| 5 | SonarQube: Code Analysis | `sonarqube_analysis("Sonar","bankapp","bankapp")` | `sonar-scanner -Dsonar.projectName=… -Dsonar.projectKey=…` | Harness `SonarqubeScanner` (STO) / `Run` step (in security step group) | +| 6 | SonarQube: Quality Gate | `sonarqube_code_quality()` | `waitForQualityGate` (1 min timeout) | `Run` step polling the Sonar quality gate API | +| 7 | Docker: Build Images | `docker_build("bankapp",TAG,"madhupdevops")` | `docker build -t madhupdevops/bankapp:TAG .` | `BuildAndPushDockerRegistry` (or Kaniko/`Run` buildx) | +| 8 | Docker: Push to DockerHub | `docker_push("bankapp",TAG,"madhupdevops")` | `docker login` + `docker push` (creds id `docker`) | Combined into `BuildAndPushDockerRegistry` with a Docker connector | +| — | `post { success }` | `archiveArtifacts '*.xml'` + trigger `BankApp-CD` | — | Harness stage artifact + next CD stage in same pipeline | + +Note: the Jenkins CI job never runs `mvn test` directly — the Maven build happens +inside the multi-stage `Dockerfile` (`mvn clean install -DskipTests=true`). The +Harness pipeline adds an **explicit Build & Test** step (`./mvnw clean test`) up +front so unit tests run and fail fast before image build, which is the intended +target state for the converged platform. + +## CD pipeline (`GitOps/Jenkinsfile`) + +| # | Jenkins stage | Command | Harness equivalent | +|---|---------------|---------|--------------------| +| 1 | Workspace cleanup | `cleanWs()` | Implicit | +| 2 | Git: Code Checkout | `code_checkout(url,"DevOps")` | `cloneCodebase` | +| 3 | Verify: Docker Image Tags | `echo DOCKER_TAG` | Pipeline variable `<+pipeline.variables.docker_tag>` | +| 4 | Update: Kubernetes manifest | `sed -i 's|…bankapp-eks:.*|…bankapp-eks:TAG|' kubernetes/bankapp-deployment.yaml` | GitOps manifest update `Run` step (or Harness GitOps ApplicationSet sync) | +| 5 | Git: update & push | commit + `git push … DevOps` (creds `Github-cred`) | `Run` step committing to the GitOps repo (or native GitOps sync) | +| — | `post { always }` | `emailext` build notification | Harness pipeline notification rule (Email/Slack) | + +## Deploy target facts (from `kubernetes/` + `helm/`) +- Namespace: `bankapp-namespace` (`kubernetes/bankapp-namespace.yaml`). +- Deployment: `bankapp-deploy`, image `trainwithshubham/bankapp-eks:` + (`kubernetes/bankapp-deployment.yml`). +- Service: `bankapp-service` on port 8080 (`kubernetes/bankapp-service.yaml`). +- Delivery model: **GitOps** — CD job rewrites the image tag in the manifest and + pushes; ArgoCD reconciles the cluster to match Git. + +## Connectors / secrets used (map these in Harness, never hard-code) +| Jenkins credential | Purpose | Harness connector/secret placeholder | +|--------------------|---------|--------------------------------------| +| `Github-cred` | Clone + GitOps push | `<+configuration>` Git/GitHub connector `account.Github` | +| `docker` | DockerHub login/push | Docker connector `account.DockerHub` | +| `Sonar` (`SONAR_HOME`, `withSonarQubeEnv`) | SonarQube server + token | SonarQube connector `account.SonarQube` + secret `sonar_token` | +| Kubeconfig (ArgoCD/EKS) | Deploy | K8s connector `account.EKS` / GitOps agent | diff --git a/.harness/README.md b/.harness/README.md new file mode 100644 index 00000000..d1973952 --- /dev/null +++ b/.harness/README.md @@ -0,0 +1,104 @@ +# Harness CI/CD — Standardized, Templated Pipelines + +This directory converges Springboot-BankApp's Jenkins DevSecOps pipeline onto +**Harness**, using **reusable templates** so other teams can onboard by supplying +a handful of variables instead of copy-pasting a `Jenkinsfile`. + +> This is **additive**. The existing `Jenkinsfile`, `GitOps/Jenkinsfile`, and +> `vars/*.groovy` shared library are left intact. Teams cut over when ready. + +## Contents + +| File | Purpose | +|------|---------| +| `pipeline.yaml` | Full CI+CD pipeline for **this** service (bankapp), built from the templates below. | +| `templates/stepgroup-security-scans.yaml` | **Step Group Template** — Trivy fs scan, OWASP Dependency-Check, SonarQube analysis + quality gate. | +| `templates/stage-ci-build-scan.yaml` | **CI Stage Template** — Build & Test (Maven) → security scans (above) → Docker build & push. | +| `templates/stage-cd-gitops-deploy.yaml` | **CD Stage Template** — verify tag → bump image in the K8s manifest → push (ArgoCD reconciles). | +| `templates/pipeline-template.yaml` | **Pipeline Template** — wires the CI + CD stage templates end-to-end; a new team creates a pipeline from this. | +| `JENKINS_INVENTORY.md` | Stage-by-stage inventory of the current Jenkins pipeline and its Harness equivalents. | + +## Reuse model (why templates) + +``` +Pipeline Template (java_service_cicd) + ├── CI Stage Template (build_scan_and_push_maven) + │ └── Step Group Template (devsecops_security_scans) ← Trivy/OWASP/Sonar + └── CD Stage Template (gitops_deploy) +``` + +The Jenkins shared library (`vars/*.groovy`) already expressed "reusable steps" +(`trivy_scan`, `owasp_dependency`, `sonarqube_analysis`, `docker_build`…). Harness +Templates are the platform-native equivalent: versioned (`versionLabel: v1`), +parameterized with runtime inputs (`<+input>`), and shareable across projects or +the whole account. + +## Jenkins → Harness stage mapping + +| Jenkins (shared-lib call) | Harness step | Where | +|---------------------------|--------------|-------| +| `code_checkout(url,"DevOps")` | `cloneCodebase: true` + Git connector | pipeline `properties.ci.codebase` | +| `trivy_scan()` | `Run` (aquasec/trivy → `trivy fs`) | step group | +| `owasp_dependency()` | `Run` (owasp/dependency-check) | step group | +| `sonarqube_analysis(...)` | `Run` (maven `sonar:sonar`) | step group | +| `sonarqube_code_quality()` | `Run` (poll Sonar quality-gate API) | step group | +| `docker_build()` + `docker_push()` | `BuildAndPushDockerRegistry` | CI stage | +| CD `sed` manifest bump + `git push` | `Run` (sed + git push, ArgoCD sync) | CD stage | +| `post{ emailext }` | `notificationRules` (Email/Slack) | pipeline | + +An explicit **Build & Test** step (`./mvnw clean test`) is added at the front of +the CI stage — the Jenkins job only compiled inside the Dockerfile with +`-DskipTests=true`, so tests never ran in CI. Running them here is the intended +converged behavior. + +## How another team onboards (Jenkins → Harness in ~10 minutes) + +1. **Import the templates.** Add the four YAMLs in `templates/` to your Harness + project (Templates page → *New Template → Import from Git*), or promote them to + **account-level** templates so every team shares one copy. Adjust + `orgIdentifier` / `projectIdentifier` to yours. +2. **Create connectors & secrets** (see next section). This is the equivalent of + Jenkins *Manage Credentials* + *Global Trusted Pipeline Libraries*. +3. **Create a pipeline from `pipeline-template.yaml`** (*Use Template*). Harness + prompts for the runtime inputs — supply your values: + + | Variable | Example | Jenkins analogue | + |----------|---------|------------------| + | `service_name` | `payments-api` | Sonar project name | + | `image_repo` | `myorg/payments-api` | `docker_build(project, …, user)` | + | `docker_tag` | `<+input>` at run time | `params.DOCKER_TAG` | + | `sonar_host_url` | `https://sonarqube.myorg.com` | SonarQube server "Sonar" | + | `sonar_project_key` | `payments-api` | `sonarqube_analysis` key | + | `image_repo` (CD) | `myorg/payments-api-eks` | image in K8s manifest | + | `gitops_repo` | `github.com/myorg/payments-api.git` | GitOps push target | + | codebase `connectorRef` / `repoName` | your Git connector / repo | `code_checkout(url,…)` | + +4. **Run it.** CI builds/tests/scans and pushes the image; CD bumps the manifest + tag and pushes so ArgoCD deploys — the same two-job flow as Jenkins, now in one + Harness pipeline. + +## Connectors & secrets (placeholders — never commit real secrets) + +Create these in Harness and reference them by identifier. The YAML uses +placeholder refs; swap them for yours. + +| Harness entity | Referenced as | Replaces Jenkins | +|----------------|---------------|------------------| +| Git/GitHub connector | `account.Github` | `Github-cred` | +| Docker registry connector | `account.DockerHub` | `docker` credential | +| Kubernetes connector | `account.EKS` | kubeconfig / ArgoCD | +| SonarQube token secret | `<+secrets.getValue("sonar_token")>` | `withSonarQubeEnv("Sonar")` | +| GitOps push token secret | `<+secrets.getValue("gitops_token")>` | `Github-cred` for push | + +Secrets live in the Harness Secret Manager (or your vault via a Secret Manager +connector). Never place real tokens in these YAML files. + +## Validation + +All YAML in this directory is well-formed and parses cleanly. Validate locally: + +```bash +python -c "import glob,yaml; [yaml.safe_load(open(f)) for f in glob.glob('.harness/**/*.yaml', recursive=True)]" +``` + +In Harness, the built-in schema validator runs when you save each pipeline/template. diff --git a/.harness/pipeline.yaml b/.harness/pipeline.yaml new file mode 100644 index 00000000..bdba49e0 --- /dev/null +++ b/.harness/pipeline.yaml @@ -0,0 +1,145 @@ +# Full Harness CI/CD pipeline for THIS service (bankapp). +# This is a concrete instantiation of the reusable stage templates in +# .harness/templates/ with bankapp's values filled in — it is exactly what an +# onboarding team produces after cloning the templates. +# +# Jenkins -> Harness stage mapping (see .harness/JENKINS_INVENTORY.md): +# Jenkinsfile (CI): checkout -> Build&Test -> Trivy -> OWASP -> Sonar -> +# Quality Gate -> Docker build -> push => stage `ci_build_scan_push` +# GitOps/Jenkinsfile (CD): verify tag -> update manifest -> git push (ArgoCD) +# => stage `cd_gitops_deploy` +pipeline: + name: BankApp CICD + identifier: bankapp_cicd + orgIdentifier: default + projectIdentifier: Springboot_BankApp + tags: + app: bankapp + source: jenkins-migration + properties: + ci: + codebase: + # Replaces Jenkins code_checkout(url,"DevOps"). Wire to your Git connector. + connectorRef: account.Github + repoName: Springboot-BankApp + build: <+input> + stages: + - stage: + identifier: ci_build_scan_push + name: CI - Build, Scan, Push + template: + templateRef: build_scan_and_push_maven + versionLabel: v1 + templateInputs: + type: CI + spec: + infrastructure: + spec: + connectorRef: account.EKS + namespace: harness-ci + execution: + steps: + - step: + identifier: build_and_test + type: Run + spec: + connectorRef: account.DockerHub + - stepGroup: + identifier: security_scans + template: + templateInputs: + type: StepGroup + spec: + stepGroupInfra: + spec: + connectorRef: account.EKS + namespace: harness-ci + steps: + - step: + identifier: trivy_fs_scan + type: Run + spec: + connectorRef: account.DockerHub + - step: + identifier: owasp_dependency_check + type: Run + spec: + connectorRef: account.DockerHub + - step: + identifier: sonarqube_analysis + type: Run + spec: + connectorRef: account.DockerHub + - step: + identifier: sonarqube_quality_gate + type: Run + spec: + connectorRef: account.DockerHub + - step: + identifier: docker_build_push + type: BuildAndPushDockerRegistry + spec: + connectorRef: account.DockerHub + variables: + - name: service_name + type: String + value: bankapp + - name: image_repo + type: String + value: madhupdevops/bankapp + - name: docker_tag + type: String + value: <+input> + - name: sonar_host_url + type: String + value: https://sonarqube.example.com + - name: sonar_project_key + type: String + value: bankapp + - stage: + identifier: cd_gitops_deploy + name: CD - GitOps Deploy + template: + templateRef: gitops_deploy + versionLabel: v1 + templateInputs: + type: CI + spec: + infrastructure: + spec: + connectorRef: account.EKS + namespace: harness-cd + execution: + steps: + - step: + identifier: verify_docker_tag + type: Run + spec: + connectorRef: account.DockerHub + - step: + identifier: update_manifest_and_push + type: Run + spec: + connectorRef: account.DockerHub + variables: + - name: docker_tag + type: String + value: <+pipeline.stages.ci_build_scan_push.variables.docker_tag> + - name: image_repo + type: String + value: trainwithshubham/bankapp-eks + - name: gitops_repo + type: String + value: github.com/COG-GTM/Springboot-BankApp.git + notificationRules: + - name: build_status + identifier: build_status + pipelineEvents: + - type: PipelineSuccess + - type: PipelineFailed + notificationMethod: + type: Email + spec: + recipients: + - platform-team@example.com + enabled: true diff --git a/.harness/templates/pipeline-template.yaml b/.harness/templates/pipeline-template.yaml new file mode 100644 index 00000000..f9d534b8 --- /dev/null +++ b/.harness/templates/pipeline-template.yaml @@ -0,0 +1,78 @@ +# Reusable Pipeline Template: end-to-end CI+CD for a Maven service on Harness. +# Wires the CI Stage Template (build_scan_and_push_maven) to the CD Stage Template +# (gitops_deploy). A NEW team onboards by creating a pipeline FROM this template +# and supplying the runtime inputs — no YAML authoring required. +template: + name: Java Service CICD (Jenkins Converged) + identifier: java_service_cicd + versionLabel: v1 + type: Pipeline + orgIdentifier: default + projectIdentifier: Springboot_BankApp + tags: + reusable: "true" + source: jenkins-migration + spec: + properties: + ci: + codebase: + connectorRef: <+input> + repoName: <+input> + build: <+input> + stages: + - stage: + identifier: ci_build_scan_push + name: CI - Build, Scan, Push + template: + templateRef: build_scan_and_push_maven + versionLabel: v1 + # All stage inputs bubble up as pipeline runtime inputs. + templateInputs: + type: CI + variables: + - name: service_name + type: String + value: <+input> + - name: image_repo + type: String + value: <+input> + - name: docker_tag + type: String + value: <+input> + - name: sonar_host_url + type: String + value: <+input> + - name: sonar_project_key + type: String + value: <+input> + - stage: + identifier: cd_gitops_deploy + name: CD - GitOps Deploy + template: + templateRef: gitops_deploy + versionLabel: v1 + templateInputs: + type: CI + variables: + - name: docker_tag + type: String + value: <+pipeline.stages.ci_build_scan_push.variables.docker_tag> + - name: image_repo + type: String + value: <+input> + - name: gitops_repo + type: String + value: <+input> + notificationRules: + - name: build_status + identifier: build_status + pipelineEvents: + - type: PipelineSuccess + - type: PipelineFailed + notificationMethod: + # Replaces the Jenkins emailext post{always} block. + type: Email + spec: + recipients: + - <+input> + enabled: true diff --git a/.harness/templates/stage-cd-gitops-deploy.yaml b/.harness/templates/stage-cd-gitops-deploy.yaml new file mode 100644 index 00000000..adb78dab --- /dev/null +++ b/.harness/templates/stage-cd-gitops-deploy.yaml @@ -0,0 +1,83 @@ +# Reusable CD Stage Template: GitOps manifest bump -> deploy. +# Reproduces the Jenkins `GitOps/Jenkinsfile` (CD job): update the image tag in +# the Kubernetes manifest, push to Git, and let ArgoCD reconcile the cluster. +template: + name: GitOps Deploy + identifier: gitops_deploy + versionLabel: v1 + type: Stage + orgIdentifier: default + projectIdentifier: Springboot_BankApp + tags: + layer: cd + reusable: "true" + spec: + type: CI + spec: + cloneCodebase: true + infrastructure: + type: KubernetesDirect + spec: + connectorRef: <+input> + namespace: <+input> + os: Linux + execution: + steps: + - step: + identifier: verify_docker_tag + name: Verify Docker Image Tag + type: Run + spec: + connectorRef: <+input> + image: alpine:3.20 + shell: Sh + command: | + # Jenkins: echo "DOCKER TAG RECEIVED: ${params.DOCKER_TAG}" + echo "DOCKER TAG RECEIVED: <+stage.variables.docker_tag>" + test -n "<+stage.variables.docker_tag>" + - step: + identifier: update_manifest_and_push + name: Update K8s Manifest and Push (GitOps) + type: Run + spec: + connectorRef: <+input> + image: alpine/git:latest + shell: Sh + envVariables: + GIT_TOKEN: <+secrets.getValue("gitops_token")> + command: | + # Jenkins: sed image tag then git commit/push to DevOps branch. + cd <+stage.variables.manifest_dir> + sed -i -e "s|<+stage.variables.image_repo>:.*|<+stage.variables.image_repo>:<+stage.variables.docker_tag>|g" \ + <+stage.variables.manifest_file> + git config user.email "harness-bot@example.com" + git config user.name "harness-bot" + git add <+stage.variables.manifest_file> + git commit -m "feature: update K8s deployment image to <+stage.variables.docker_tag>" || echo "no changes" + git push "https://${GIT_TOKEN}@<+stage.variables.gitops_repo>" HEAD:<+stage.variables.gitops_branch> + # ArgoCD then reconciles the cluster to match Git (GitOps CD). + variables: + - name: docker_tag + type: String + value: <+input> + description: Image tag produced by the CI stage. + - name: image_repo + type: String + value: <+input> + description: Image repo referenced in the manifest (e.g. trainwithshubham/bankapp-eks). + - name: manifest_dir + type: String + value: kubernetes + description: Directory holding the deployment manifest. + - name: manifest_file + type: String + value: bankapp-deployment.yml + description: Manifest file whose image tag is rewritten. + - name: gitops_repo + type: String + value: <+input> + description: GitOps repo host/path, e.g. github.com/org/Springboot-BankApp.git. + - name: gitops_branch + type: String + value: DevOps + description: Branch ArgoCD watches. diff --git a/.harness/templates/stage-ci-build-scan.yaml b/.harness/templates/stage-ci-build-scan.yaml new file mode 100644 index 00000000..71f32132 --- /dev/null +++ b/.harness/templates/stage-ci-build-scan.yaml @@ -0,0 +1,116 @@ +# Reusable CI Stage Template: Build & Test -> Security Scans -> Docker build+push. +# Reproduces the whole Jenkins `Jenkinsfile` (CI job) for ANY Java/Maven service. +# Onboarding teams reference this template and supply the stage variables only. +template: + name: Build Scan and Push (Maven) + identifier: build_scan_and_push_maven + versionLabel: v1 + type: Stage + orgIdentifier: default + projectIdentifier: Springboot_BankApp + tags: + layer: ci + reusable: "true" + spec: + type: CI + # cloneCodebase replaces the Jenkins code_checkout() shared-lib step. + spec: + cloneCodebase: true + infrastructure: + type: KubernetesDirect + spec: + connectorRef: <+input> + namespace: <+input> + automountServiceAccountToken: true + nodeSelector: {} + os: Linux + execution: + steps: + - step: + identifier: build_and_test + name: Build and Test (Maven) + type: Run + spec: + connectorRef: <+input> + image: maven:3.8.3-openjdk-17 + shell: Sh + command: | + # Explicit unit tests up front (Jenkins built these only inside + # the Dockerfile with -DskipTests=true). Fail fast on test break. + ./mvnw -B clean test + - stepGroup: + identifier: security_scans + name: DevSecOps Security Scans + template: + templateRef: devsecops_security_scans + versionLabel: v1 + templateInputs: + type: StepGroup + spec: + stepGroupInfra: + type: KubernetesDirect + spec: + connectorRef: <+input> + namespace: <+input> + steps: + - step: + identifier: trivy_fs_scan + type: Run + spec: + connectorRef: <+input> + - step: + identifier: owasp_dependency_check + type: Run + spec: + connectorRef: <+input> + - step: + identifier: sonarqube_analysis + type: Run + spec: + connectorRef: <+input> + - step: + identifier: sonarqube_quality_gate + type: Run + spec: + connectorRef: <+input> + - step: + identifier: docker_build_push + name: Docker Build and Push + type: BuildAndPushDockerRegistry + spec: + # Jenkins: docker_build()/docker_push() with creds id `docker`. + connectorRef: <+input> + repo: <+stage.variables.image_repo> + tags: + - <+stage.variables.docker_tag> + - latest + dockerfile: <+stage.variables.dockerfile> + context: . + sharedPaths: + - /var/run + # Variables an onboarding team overrides — this is the entire contract. + variables: + - name: service_name + type: String + value: <+input> + description: Logical service name (Sonar project name, OWASP project). + - name: image_repo + type: String + value: <+input> + description: Container image repository, e.g. madhupdevops/bankapp. + - name: docker_tag + type: String + value: <+input> + description: Image tag to build/push (Jenkins DOCKER_TAG parameter). + - name: dockerfile + type: String + value: Dockerfile + description: Path to the Dockerfile. + - name: sonar_host_url + type: String + value: <+input> + description: SonarQube server URL. + - name: sonar_project_key + type: String + value: <+input> + description: SonarQube project key (Jenkins passed "bankapp"). diff --git a/.harness/templates/stepgroup-security-scans.yaml b/.harness/templates/stepgroup-security-scans.yaml new file mode 100644 index 00000000..7674df1b --- /dev/null +++ b/.harness/templates/stepgroup-security-scans.yaml @@ -0,0 +1,88 @@ +# Reusable Step Group Template: DevSecOps security scans. +# Reproduces the Jenkins shared-lib steps trivy_scan(), owasp_dependency(), +# sonarqube_analysis() and sonarqube_code_quality() as one drop-in unit. +# Any team's CI stage can reference this template and only supply variables. +template: + name: DevSecOps Security Scans + identifier: devsecops_security_scans + versionLabel: v1 + type: StepGroup + # Replace with your Harness org/project (or promote to account-level template). + orgIdentifier: default + projectIdentifier: Springboot_BankApp + tags: + layer: security + reusable: "true" + spec: + # Runs inside a CI stage's Kubernetes/hosted infrastructure. + stepGroupInfra: + type: KubernetesDirect + spec: + connectorRef: <+input> + namespace: <+input> + steps: + - step: + identifier: trivy_fs_scan + name: Trivy Filesystem Scan + type: Run + spec: + connectorRef: <+input> + image: aquasec/trivy:latest + shell: Sh + command: | + # Jenkins: trivy_scan() -> `trivy fs .` + trivy fs --exit-code 0 --severity HIGH,CRITICAL --format table . + - step: + identifier: owasp_dependency_check + name: OWASP Dependency Check + type: Run + spec: + connectorRef: <+input> + image: owasp/dependency-check:latest + shell: Sh + command: | + # Jenkins: owasp_dependency() -> dependencyCheck --scan ./ + /usr/share/dependency-check/bin/dependency-check.sh \ + --scan ./ \ + --format XML \ + --project "<+stage.variables.service_name>" \ + --out . + # Publishes dependency-check-report.xml (Jenkins archiveArtifacts equiv). + - step: + identifier: sonarqube_analysis + name: SonarQube Code Analysis + type: Run + spec: + connectorRef: <+input> + image: maven:3.8.3-openjdk-17 + shell: Sh + envVariables: + SONAR_HOST_URL: <+stage.variables.sonar_host_url> + SONAR_TOKEN: <+secrets.getValue("sonar_token")> + command: | + # Jenkins: sonarqube_analysis("Sonar","bankapp","bankapp") + ./mvnw -B verify sonar:sonar \ + -Dsonar.projectKey=<+stage.variables.sonar_project_key> \ + -Dsonar.projectName=<+stage.variables.service_name> \ + -Dsonar.host.url=${SONAR_HOST_URL} \ + -Dsonar.login=${SONAR_TOKEN} + - step: + identifier: sonarqube_quality_gate + name: SonarQube Quality Gate + type: Run + timeout: 5m + spec: + connectorRef: <+input> + image: curlimages/curl:latest + shell: Sh + envVariables: + SONAR_HOST_URL: <+stage.variables.sonar_host_url> + SONAR_TOKEN: <+secrets.getValue("sonar_token")> + command: | + # Jenkins: sonarqube_code_quality() -> waitForQualityGate + status=$(curl -s -u "${SONAR_TOKEN}:" \ + "${SONAR_HOST_URL}/api/qualitygates/project_status?projectKey=<+stage.variables.sonar_project_key>" \ + | grep -o '"status":"[A-Z]*"' | head -1 | cut -d'"' -f4) + echo "Quality gate status: ${status}" + # abortPipeline:false in Jenkins -> do not hard-fail here. + if [ "${status}" = "ERROR" ]; then echo "Quality gate FAILED (non-blocking)"; fi