ci: SonarQube-сканування (self-hosted) - #3
vaulttec-dev wants to merge 2 commits into
Conversation
📝 WalkthroughWalkthroughДодано конфігурацію SonarQube та workflow GitHub Actions для аналізу гілки ChangesІнтеграція SonarQube
Estimated code review effort: 4 (Complex) | ~45 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
Pull request overview
Adds a self-hosted SonarQube scan to this repository’s CI so PRs and main pushes can be analyzed, with a “graceful skip” behavior until required secrets are configured.
Changes:
- Introduces a GitHub Actions workflow to run SonarQube scans for PRs and branches and post/update a sticky PR comment with findings.
- Adds
sonar-project.propertiesto define scan scope (sources, exclusions) and test inclusion globs.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
.github/workflows/sonarqube.yml |
New CI workflow for SonarQube scanning + PR comment reporting. |
sonar-project.properties |
SonarQube project configuration (sources/exclusions/tests). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # SonarQube scanner config. Server/onboarding: eloicompany/sonarqube-selfhosted repo. | ||
| sonar.projectKey=chrome-extension | ||
| sonar.sources=. |
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
|
|
| # --- OPTIONAL: coverage for the scanner ----------------------------- | ||
| # Customise or delete per project. If you generate an lcov report here, | ||
| # point sonar.javascript.lcov.reportPaths at it in sonar-project.properties. | ||
| # Note: vitest writes SF: paths relative to its cwd, while SonarQube resolves | ||
| # them relative to the repo root — rewrite the prefix if they differ, e.g. | ||
| # sed -i 's|^SF:|SF:apps/<app>/|' <path>/coverage/lcov.info | ||
| # | ||
| # - name: 🟢 Setup Node and pnpm | ||
| # if: steps.creds.outputs.present == 'true' | ||
| # uses: ./.github/actions/setup-node-pnpm | ||
| # with: | ||
| # node-version: '22' | ||
| # - name: 🧪 Generate coverage | ||
| # if: steps.creds.outputs.present == 'true' | ||
| # run: pnpm test:coverage || true | ||
|
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/sonarqube.yml:
- Around line 50-58: Update the SonarQube prerequisite check to require only
SONAR_TOKEN, while sourcing SONAR_HOST_URL from the centralized
organization/repository variable or a fixed workflow value. Ensure repositories
configured with just the token set present=true and continue passing the
automatically configured SONAR_PROJECT_KEY and host URL to the scan.
- Around line 106-125: Update the quality-gate polling step to read ceTaskId
from report-task.txt, poll the Sonar Compute Engine task until it reaches
SUCCESS, and then query project_status using that task’s analysisId instead of
only projectKey and PR_NUMBER. If the report metadata is missing or the task
does not complete successfully, skip posting the PR comment; preserve the
existing comment flow for a successfully resolved current analysis.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d974ec54-5533-4eae-ae0f-ec79033d8f9c
📒 Files selected for processing (2)
.github/workflows/sonarqube.ymlsonar-project.properties
| env: | ||
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
| SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} | ||
| run: | | ||
| if [ -n "$SONAR_TOKEN" ] && [ -n "$SONAR_HOST_URL" ]; then | ||
| echo "present=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "present=false" >> $GITHUB_OUTPUT | ||
| echo "⚠️ **SonarQube skipped — SONAR_TOKEN / SONAR_HOST_URL secrets are not set**" >> $GITHUB_STEP_SUMMARY |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Не вимагайте ручного секрету SONAR_HOST_URL.
За цілями PR автоматично налаштовуються SONAR_HOST_URL і SONAR_PROJECT_KEY, а вручну додається лише SONAR_TOKEN. Наразі репозиторій із одним токеном завжди отримує present=false і пропускає сканування. Передавайте URL через централізовану organization/repository variable або зафіксуйте адресу сервера у workflow.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/sonarqube.yml around lines 50 - 58, Update the SonarQube
prerequisite check to require only SONAR_TOKEN, while sourcing SONAR_HOST_URL
from the centralized organization/repository variable or a fixed workflow value.
Ensure repositories configured with just the token set present=true and continue
passing the automatically configured SONAR_PROJECT_KEY and host URL to the scan.
| if: always() && github.event_name == 'pull_request' && steps.creds.outputs.present == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
| SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} | ||
| PR_NUMBER: ${{ github.event.pull_request.number }} | ||
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| run: | | ||
| # The scan step no longer waits on sonar.qualitygate.wait, so the gate | ||
| # may still be computing server-side when this step starts — poll | ||
| # briefly instead of a single immediate check. | ||
| GATE="UNAVAILABLE" | ||
| for _ in $(seq 1 12); do | ||
| if RESP=$(curl -sf -u "$SONAR_TOKEN:" \ | ||
| "$SONAR_HOST_URL/api/qualitygates/project_status?projectKey=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER"); then | ||
| GATE=$(echo "$RESP" | jq -r '.projectStatus.status // "NONE"') | ||
| [ "$GATE" != "NONE" ] && break | ||
| fi | ||
| sleep 5 | ||
| done |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n 'report-task|ceTaskId|analysisId|qualitygates/project_status|always\(\)' \
.github/workflows/sonarqube.ymlRepository: vaulttec-dev/chrome-extension
Length of output: 400
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=".github/workflows/sonarqube.yml"
wc -l "$file"
sed -n '90,170p' "$file" | cat -nRepository: vaulttec-dev/chrome-extension
Length of output: 4966
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=".github/workflows/sonarqube.yml"
sed -n '1,120p' "$file" | cat -nRepository: vaulttec-dev/chrome-extension
Length of output: 6013
🌐 Web query:
SonarQube API /api/qualitygates/project_status pullRequest analysisId semantics latest analysis report-task.txt ceTaskId
💡 Result:
To programmatically check the Quality Gate status of a SonarQube analysis, you must interact with the asynchronous analysis process [1][2]. The report-task.txt file, generated in the scanner's working directory upon successful submission, provides the necessary entry point [3][4][5]. Process Overview: 1. Identify the ceTaskId: After the SonarScanner finishes submitting the report, a report-task.txt file is created containing the ceTaskId (Compute Engine Task ID) [3][1]. 2. Monitor Task Completion: Use the /api/ce/task endpoint with the ceTaskId to poll the status of the background analysis [1][2]. GET /api/ce/task?id= Continue polling until the task.status field returns "SUCCESS" [1][2]. 3. Retrieve analysisId: Once the status is "SUCCESS", the same /api/ce/task response will contain the analysisId (located in task.analysisId) [1][2]. 4. Get Quality Gate Status: Use the analysisId with the /api/qualitygates/project_status endpoint to get the final result [6][3][2]. GET /api/qualitygates/project_status?analysisId= Regarding /api/qualitygates/project_status and Pull Requests: While you can query this endpoint using projectKey and branch/pullRequest parameters (e.g., /api/qualitygates/project_status?projectKey=&pullRequest=), these requests may return inconsistent or summary-only data depending on your environment and authentication method [7][6]. For precise, reliable results—especially when automating CI/CD pipelines—it is considered best practice to use the analysisId obtained from the specific background task, as it ensures you are checking the status of the exact analysis just completed [6][1]. Top Results: [6][3][1][2]
Citations:
- 1: https://community.sonarsource.com/t/ant-quality-gate/41655
- 2: https://github.com/PublicisSapient/knowhow-processors/blob/master/SonarQG.sh
- 3: https://stackoverflow.com/questions/34758525/how-to-get-analysisid-in-sonar
- 4: https://stackoverflow.com/questions/48232628/sonar-scanner-report-file-with-taskid-and-analysisid
- 5: https://stackoverflow.com/questions/67737102/get-sonarqube-analysis-status-on-a-variable-gui-job
- 6: https://community.sonarsource.com/t/qualitygate-api-results-are-inconsistent/21634
- 7: https://community.sonarsource.com/t/how-to-get-the-quality-gate-satus-and-the-revision-of-an-analysed-pr-over-web-api/88216
🌐 Web query:
SonarQube qualitygates/project_status pullRequest returns latest analysis or previous analysis while background task still running
💡 Result:
When calling the SonarQube API endpoint api/qualitygates/project_status while a background task is still in progress, the API will return the status of the most recently completed analysis [1][2][3]. It does not automatically wait for or return the results of the pending analysis currently being processed by the compute engine [4][5]. Because the analysis is not fully incorporated into the project state until its corresponding background task completes (reaching a status of SUCCESS), any API call made before that completion will reflect the state from the previous, finished analysis [4][6][5]. To ensure you are retrieving the results of the specific, ongoing analysis, you should use one of the following methods: 1. Use sonar.qualitygate.wait=true: Adding this parameter to your scanner execution forces the analysis process to wait until the background task is fully processed by the SonarQube server before exiting [6][5]. This is generally the most robust approach for CI/CD pipelines [6]. 2. Poll the Background Task API: After the scanner finishes, you can use the ceTaskId (available in the report-task.txt file generated by the scanner) to poll the api/ce/task endpoint [7][2][8]. Once the task status is SUCCESS, you can then safely call api/qualitygates/project_status using the analysisId returned by the task status response [7][8]. 3. Monitor via Webhooks: Configure SonarQube webhooks to notify your system once a background task completes [9][10]. This avoids the need for polling altogether by pushing the result to you when it is ready [9]. Attempting to check the quality gate status immediately after the scanner finishes without waiting for the background task will frequently result in receiving "stale" or inaccurate data [1][3].
Citations:
- 1: https://community.sonarsource.com/t/sonarquality-gate-api-issue/29192
- 2: https://community.sonarsource.com/t/qualitygate-api-results-are-inconsistent/21634
- 3: https://community.sonarsource.com/t/how-to-get-new-quality-gate-values-when-re-evaluate-pull-requests/49857
- 4: https://docs.sonarsource.com/sonarqube-server/2026.2/analyzing-source-code/background-tasks
- 5: https://community.sonarsource.com/t/api-quality-gates/19281
- 6: https://community.sonarsource.com/t/mismatch-between-sonarqube-server-state-and-api-response-after-pr-reanalysis-in-ci-cd-pipeline/149684
- 7: https://community.sonarsource.com/t/background-task-statuses/16356
- 8: https://stackoverflow.com/questions/40504535/how-to-react-on-sonarqube-quality-gate-within-jenkins-pipeline
- 9: https://community.sonarsource.com/t/quality-gates-dont-fail/19779
- 10: https://community.sonarsource.com/t/deprecated-qualitygates-project-status-endpoint-has-no-v2-equivalent/181235
Прив’яжіть PR-коментар до поточного Sonar task
Запит лише за projectKey і pullRequest може показати попередній завершений аналіз, якщо поточний background task ще обробляється. Зчитайте ceTaskId з report-task.txt, дочекайтеся SUCCESS для цього task і беріть project_status за analysisId; без метаданих цього запуску коментар краще пропускати.
🧰 Tools
🪛 Betterleaks (1.6.1)
[high] 119-119: Discovered a potential basic authorization token provided in a curl command, which could compromise the curl accessed resource.
(curl-auth-user)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/sonarqube.yml around lines 106 - 125, Update the
quality-gate polling step to read ceTaskId from report-task.txt, poll the Sonar
Compute Engine task until it reaches SUCCESS, and then query project_status
using that task’s analysisId instead of only projectKey and PR_NUMBER. If the
report metadata is missing or the task does not complete successfully, skip
posting the PR comment; preserve the existing comment flow for a successfully
resolved current analysis.
|
|
||
| # Sticky PR comment (updated in place, not re-posted) with the findings | ||
| - name: 💬 Comment findings on PR | ||
| if: always() && github.event_name == 'pull_request' && steps.creds.outputs.present == 'true' |
There was a problem hiding this comment.
Публікація застарілого результату
always() запускає цей крок після помилки або скасування поточного scan. Оскільки наступні API-запити прив’язані лише до project key і номера PR, вони можуть отримати попередній завершений аналіз та опублікувати його як результат поточного commit.
| if: always() && github.event_name == 'pull_request' && steps.creds.outputs.present == 'true' | |
| if: success() && github.event_name == 'pull_request' && steps.creds.outputs.present == 'true' |
| if ! curl -sf -u "$SONAR_TOKEN:" \ | ||
| "$SONAR_HOST_URL/api/issues/search?components=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER&resolved=false&ps=100" \ | ||
| > "$ISSUES_FILE"; then |
There was a problem hiding this comment.
Звіт обрізається на 100 issues
ps=100 завантажує лише першу сторінку, тоді як код використовує довжину отриманого масиву як загальну кількість. Для PR із понад 100 issues коментар покаже неправильний підсумок і повністю приховає решту результатів; потрібно обходити сторінки або брати загальну кількість із paging.total.
|
|
||
| ISSUES_FILE=$(mktemp) | ||
| if ! curl -sf -u "$SONAR_TOKEN:" \ | ||
| "$SONAR_HOST_URL/api/issues/search?components=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER&resolved=false&ps=100" \ |
There was a problem hiding this comment.
Несумісний параметр фільтра API
Запит використовує застарілий параметр components, тоді як актуальний контракт /api/issues/search очікує componentKeys. На сервері без сумісного alias запит завершиться помилкою, після чого гілка exit 0 пропустить PR-коментар і залишить workflow успішним без результатів аналізу.
| "$SONAR_HOST_URL/api/issues/search?components=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER&resolved=false&ps=100" \ | |
| "$SONAR_HOST_URL/api/issues/search?componentKeys=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER&resolved=false&ps=100" \ |
There was a problem hiding this comment.
3 issues found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".github/workflows/sonarqube.yml">
<violation number="1" location=".github/workflows/sonarqube.yml:122">
P2: PR reruns can update the sticky comment with the previous analysis’s gate and issues. Poll the submitted Compute Engine task (or otherwise wait for this scan’s analysis) before fetching `project_status` and issues.</violation>
<violation number="2" location=".github/workflows/sonarqube.yml:129">
P3: PR comments undercount findings once a PR has over 100 unresolved issues, while presenting the truncated count as total. Use the response `total` and paginate, or label the result as the first 100 findings.</violation>
</file>
<file name="sonar-project.properties">
<violation number="1" location="sonar-project.properties:2">
P2: `sonar.projectKey` is hardcoded here as `chrome-extension`, but the workflow also passes `-Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }}` (which defaults to the repo name or a variable). Having two sources of truth means local scans and CI could silently target different projects if either value drifts. Consider removing the hardcoded key from this file and relying solely on the CI-provided value (or vice versa).</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| if RESP=$(curl -sf -u "$SONAR_TOKEN:" \ | ||
| "$SONAR_HOST_URL/api/qualitygates/project_status?projectKey=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER"); then | ||
| GATE=$(echo "$RESP" | jq -r '.projectStatus.status // "NONE"') | ||
| [ "$GATE" != "NONE" ] && break |
There was a problem hiding this comment.
P2: PR reruns can update the sticky comment with the previous analysis’s gate and issues. Poll the submitted Compute Engine task (or otherwise wait for this scan’s analysis) before fetching project_status and issues.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/sonarqube.yml, line 122:
<comment>PR reruns can update the sticky comment with the previous analysis’s gate and issues. Poll the submitted Compute Engine task (or otherwise wait for this scan’s analysis) before fetching `project_status` and issues.</comment>
<file context>
@@ -0,0 +1,172 @@
+ if RESP=$(curl -sf -u "$SONAR_TOKEN:" \
+ "$SONAR_HOST_URL/api/qualitygates/project_status?projectKey=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER"); then
+ GATE=$(echo "$RESP" | jq -r '.projectStatus.status // "NONE"')
+ [ "$GATE" != "NONE" ] && break
+ fi
+ sleep 5
</file context>
| @@ -0,0 +1,15 @@ | |||
| # SonarQube scanner config. Server/onboarding: eloicompany/sonarqube-selfhosted repo. | |||
| sonar.projectKey=chrome-extension | |||
There was a problem hiding this comment.
P2: sonar.projectKey is hardcoded here as chrome-extension, but the workflow also passes -Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }} (which defaults to the repo name or a variable). Having two sources of truth means local scans and CI could silently target different projects if either value drifts. Consider removing the hardcoded key from this file and relying solely on the CI-provided value (or vice versa).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At sonar-project.properties, line 2:
<comment>`sonar.projectKey` is hardcoded here as `chrome-extension`, but the workflow also passes `-Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }}` (which defaults to the repo name or a variable). Having two sources of truth means local scans and CI could silently target different projects if either value drifts. Consider removing the hardcoded key from this file and relying solely on the CI-provided value (or vice versa).</comment>
<file context>
@@ -0,0 +1,15 @@
+# SonarQube scanner config. Server/onboarding: eloicompany/sonarqube-selfhosted repo.
+sonar.projectKey=chrome-extension
+sonar.sources=.
+sonar.exclusions=\
</file context>
| sonar.projectKey=chrome-extension | |
| # sonar.projectKey is provided by CI via -Dsonar.projectKey; set here only for local scans. | |
| # sonar.projectKey=chrome-extension |
|
|
||
| ISSUES_FILE=$(mktemp) | ||
| if ! curl -sf -u "$SONAR_TOKEN:" \ | ||
| "$SONAR_HOST_URL/api/issues/search?components=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER&resolved=false&ps=100" \ |
There was a problem hiding this comment.
P3: PR comments undercount findings once a PR has over 100 unresolved issues, while presenting the truncated count as total. Use the response total and paginate, or label the result as the first 100 findings.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/sonarqube.yml, line 129:
<comment>PR comments undercount findings once a PR has over 100 unresolved issues, while presenting the truncated count as total. Use the response `total` and paginate, or label the result as the first 100 findings.</comment>
<file context>
@@ -0,0 +1,172 @@
+
+ ISSUES_FILE=$(mktemp)
+ if ! curl -sf -u "$SONAR_TOKEN:" \
+ "$SONAR_HOST_URL/api/issues/search?components=$SONAR_PROJECT_KEY&pullRequest=$PR_NUMBER&resolved=false&ps=100" \
+ > "$ISSUES_FILE"; then
+ echo "::warning::SonarQube API unavailable — skipping PR comment"
</file context>



Додає self-hosted SonarQube:
.github/workflows/sonarqube.yml(параметризований) +sonar-project.properties(projectKeychrome-extension).SONAR_HOST_URLтаSONAR_PROJECT_KEYвиставлено автоматично (host✓, key✓).SONAR_TOKEN(глобальний analysis-токен) — до нього workflow gracefully skip-иться (не червонить CI).eloicompany/sonarqube-selfhosted.Частина уніфікації CI на всі проєкти.
Summary by cubic
Add self-hosted SonarQube scanning to CI with a reusable workflow and project config. It comments findings on PRs and skips gracefully until required secrets are set.
New Features
.github/workflows/sonarqube.ymlfor PR and branch analysis usingsonarsource/sonarqube-scan-action@v8.2.0, with concurrency and no quality gate blocking.vars.SONAR_PROJECT_KEY(falls back to repo name); optional coverage step documented.SONAR_TOKENorSONAR_HOST_URLare missing.sonar-project.propertieswith sources, exclusions, and test globs.Migration
SONAR_TOKEN,SONAR_HOST_URL.SONAR_PROJECT_KEY(defaults to repo name).sonar-project.propertiesand enable the optional steps.Written for commit c1037a0. Summary will update on new commits.
Summary by CodeRabbit
Нові можливості
Конфігурація
Greptile Summary
Цей PR додає self-hosted SonarQube-аналіз для основної гілки та pull request. Основні зміни:
Confidence Score: 4/5
Шлях публікації PR-звіту потребує виправлення перед злиттям: він може показати застарілий або обрізаний результат.
.github/workflows/sonarqube.yml
Important Files Changed
Reviews (1): Last reviewed commit: "ci: конфіг сканера SonarQube" | Re-trigger Greptile