address comments
diff --git a/.github/workflows/main-sonar-check.yml b/.github/workflows/main-sonar-check.yml
index fe4fa18..ee2da19 100644
--- a/.github/workflows/main-sonar-check.yml
+++ b/.github/workflows/main-sonar-check.yml
@@ -38,3 +38,4 @@
       is_pr: false
     secrets:
       SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/sonar-check.yml b/.github/workflows/sonar-check.yml
index 5ea1f66..3d4b29a 100644
--- a/.github/workflows/sonar-check.yml
+++ b/.github/workflows/sonar-check.yml
@@ -29,9 +29,9 @@
 
 jobs:
   sonar:
-    if: github.repository == 'apache/cloudstack' && github.event.pull_request.head.repo.full_name == github.repository
     uses: ./.github/workflows/sonar-reusable.yml
     with:
       is_pr: true
     secrets:
       SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/sonar-reusable.yml b/.github/workflows/sonar-reusable.yml
index d2af899..264ec7a 100644
--- a/.github/workflows/sonar-reusable.yml
+++ b/.github/workflows/sonar-reusable.yml
@@ -27,6 +27,8 @@
     secrets:
       SONAR_TOKEN:
         required: false
+      CODECOV_TOKEN:
+        required: false
 
 permissions:
   contents: read
@@ -35,30 +37,29 @@
 jobs:
   build:
     name: Sonar JaCoCo Coverage
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
     steps:
-      # PR callers check out the merge commit; branch callers use the pushed SHA.
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
         with:
           ref: ${{ inputs.is_pr && format('refs/pull/{0}/merge', github.event.number) || github.sha }}
           fetch-depth: 0
+          persist-credentials: false
 
-      - name: Set up JDK17
-        uses: actions/setup-java@v5
+      - name: Setup Environment
+        uses: ./.github/actions/setup-env
         with:
-          distribution: 'temurin'
-          java-version: '17'
-          cache: 'maven'
+          install-python: 'true'
+          install-apt-deps: 'true'
 
       - name: Cache SonarCloud packages
-        uses: actions/cache@v5
+        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
         with:
           path: ~/.sonar/cache
           key: ${{ runner.os }}-sonar
           restore-keys: ${{ runner.os }}-sonar
 
       - name: Cache local Maven repository
-        uses: actions/cache@v5
+        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
         with:
           path: ~/.m2/repository
           key: ${{ runner.os }}-m2-${{ hashFiles('pom.xml', '*/pom.xml', '*/*/pom.xml', '*/*/*/pom.xml') }}
@@ -66,33 +67,33 @@
             ${{ runner.os }}-m2
 
       - name: Install Non-OSS
-        run: |
-          git clone https://github.com/shapeblue/cloudstack-nonoss.git nonoss
-          cd nonoss && bash -x install-non-oss.sh && cd ..
+        uses: ./.github/actions/install-nonoss
 
-      - name: Run Build and Tests with Coverage (PR)
-        if: inputs.is_pr
+      - name: Run Build and Tests with Coverage
+        run: mvn -B -T$(nproc) -P developer,systemvm,quality -Dsimulator -Dnoredist clean install
+
+      - name: Upload to SonarQube
+        if: inputs.is_pr && github.repository == 'apache/cloudstack' && github.event.pull_request.head.repo.full_name == github.repository
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
           PR_ID: ${{ github.event.pull_request.number }}
           HEADREF: ${{ github.event.pull_request.head.ref }}
-        run: >
-          mvn -T$(nproc) -P quality -Dsimulator -Dnoredist clean install
-          org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
-          -Dsonar.projectKey=apache_cloudstack
-          -Dsonar.pullrequest.key="$PR_ID"
-          -Dsonar.pullrequest.branch="$HEADREF"
-          -Dsonar.pullrequest.github.repository=apache/cloudstack
-          -Dsonar.pullrequest.provider=GitHub
-          -Dsonar.pullrequest.github.summary_comment=true
+        run: |
+          mvn -B -P quality org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=apache_cloudstack -Dsonar.pullrequest.key="$PR_ID" -Dsonar.pullrequest.branch="$HEADREF" -Dsonar.pullrequest.github.repository=apache/cloudstack -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.summary_comment=true
 
-      - name: Run Tests with Coverage (Main)
+      - name: Upload to SonarQube
         if: "!inputs.is_pr"
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
-        run: >
-          mvn -T$(nproc) -P quality -Dsimulator -Dnoredist clean install
-          org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
-          -Dsonar.projectKey=apache_cloudstack
+        run: mvn -B -P quality org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=apache_cloudstack -Dsonar.branch.name=${{ github.ref_name }}
+
+      - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
+        with:
+          files: ./client/target/site/jacoco-aggregate/jacoco.xml
+          fail_ci_if_error: true
+          flags: unittests
+          verbose: true
+          name: codecov
+          token: ${{ secrets.CODECOV_TOKEN }}