Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .harness/JENKINS_INVENTORY.md
Original file line number Diff line number Diff line change
@@ -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:<tag>`
(`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 |
104 changes: 104 additions & 0 deletions .harness/README.md
Original file line number Diff line number Diff line change
@@ -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.
145 changes: 145 additions & 0 deletions .harness/pipeline.yaml
Original file line number Diff line number Diff line change
@@ -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
78 changes: 78 additions & 0 deletions .harness/templates/pipeline-template.yaml
Original file line number Diff line number Diff line change
@@ -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
Loading