Start your free trial
Verify all code. Find and fix issues faster with SonarQube.
LoslegenTL;DR overview
- Pairing Gitar with SonarQube Cloud gives every pull request two independent verification layers: LLM-based review that fixes CI failures, and deterministic analysis that catches security vulnerabilities at zero token cost.
- Both tools independently detect the same path traversal vulnerability through different methods, while each catches issue types the other may not reach.
- Gitar's fix commits trigger automatic SonarQube rescans, so resolved findings clear without manual intervention. The two tools operate as independent, parallel paths on the same pull request.
- After Gitar fixes its findings and approves the PR, SonarQube's quality gate still blocks on security issues the AI never flagged.
Overview
Two independent verification layers on a single GitHub repository: Gitar for LLM-based code review and CI auto-fix, SonarQube Cloud for deterministic static analysis and quality gate enforcement. Neither tool knows about the other. They run on the same PR, catch different classes of problems, and report independently.
Gitar analyzes CI logs and code diffs, then pushes fix commits to the PR branch. SonarQube traces data flows through your code to detect security vulnerabilities that don't break tests, then blocks the PR if the quality gate fails. SonarQube's analysis consumes zero LLM tokens.
When to use AI code review with static analysis
You want CI failures fixed automatically and security vulnerabilities caught before merge, without relying on a single detection method. AI code review catches logic errors and test failures that require understanding intent. Deterministic analysis catches taint flows, insecure configurations, and policy violations the LLM may not flag.
What you'll see
- Gitar automatically analyzes CI failures and pushes fix commits to the PR branch
- SonarQube catches security vulnerabilities through taint analysis at zero token cost
- Both tools independently find the same path traversal vulnerability through fundamentally different methods (LLM code review and data flow analysis)
- The quality gate blocks merge on issues the AI review didn't flag
Architecture

SonarQube runs as a step inside GitHub Actions CI. When the scan action executes, it sends code to SonarQube Cloud's analysis engine, which traces data flows, applies security rules, and returns a quality gate result that decorates the PR.
Gitar runs outside CI entirely. The GitHub App receives PR events via webhook, and Gitar's cloud agent analyzes the code diff and CI logs independently. When it pushes a fix commit, CI re-triggers, and SonarQube rescans automatically.
The two paths converge on the PR but never intersect. The developer sees Gitar's review comments and approval status alongside SonarQube's quality gate result as two independent assessments.
Prerequisites
- A GitHub organization with permissions to install GitHub Apps and add secrets
- A SonarQube Cloud account
- A Gitar account with the GitHub App installed on your organization. Auto-apply (automatic fix commits) requires a Gitar Pro plan. The Core tier includes CI failure analysis and review comments but not fix commits. See the Gitar quickstart for installation.
- Python 3.12+ (or adjust the version in the CI workflow to match your project)
This blueprint uses a Python/Flask demo app with pytest on GitHub Actions. The pattern applies to any language SonarQube Cloud supports and any repository on GitHub or GitLab.
Step 1 — Demo repository with failing tests and a hidden vulnerability
The demo repository we used is a Python/Flask task tracker API. The main branch has correct code with passing tests. The add-pagination-and-sorting branch introduces two buggy utility functions, three test failures, and a CSV export endpoint with a path traversal vulnerability that has no test coverage.
The two bugs are straightforward. paginate_tasks uses page * page_size as the start offset instead of (page - 1) * page_size, so page 1 returns the second page of results. sort_by_deadline sorts descending when the tests expect ascending. Three tests catch these bugs but there are none for the export endpoint.
That endpoint takes a user-supplied filename from the request and passes it through os.path.join into open:
def export_tasks_to_csv(tasks, export_dir, filename):
filepath = os.path.join(export_dir, filename)
os.makedirs(export_dir, exist_ok=True)
with open(filepath, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["id", "title", "status", "deadline"])
for task in tasks:
writer.writerow([task["id"], task["title"], task["status"], task["deadline"]])
return filepathThe route passes request.args.get("filename") directly to this function:
@app.route("/api/tasks/export")
def export_tasks():
filename = request.args.get("filename", "tasks.csv")
filepath = export_tasks_to_csv(tasks_db, "/tmp/exports", filename)
return jsonify({"exported_to": filepath, "count": len(tasks_db)})The code looks safe on inspection as os.path.join and csv.writer are both standard library, and the function signature is clean. But os.path.join("/tmp/exports", "../../etc/cron.d/evil") produces /tmp/exports/../../etc/cron.d/evil, and when open() uses that string, the OS resolves it to /etc/cron.d/evil. The taint flow crosses two files and three function calls: request.args.get("filename") → export_tasks_to_csv() → os.path.join() → open().
On the feature branch, pytest -v shows three failures (test_paginate_first_page, test_paginate_second_page, test_sort_by_deadline_ascending) with all other tests passing.
Step 2 — SonarQube Cloud scan running in CI
When setting things up for yourself, first import the repository into SonarQube Cloud:
- Click + then Analyze new project
- Select your GitHub organization and the repository
- Choose With GitHub Actions as the analysis method
Add sonar-project.properties to the repository root:
sonar.projectKey=<YOUR_ORG>_<YOUR_REPO>
sonar.organization=<YOUR_ORG><YOUR_ORG> is your SonarQube Cloud organization key. <YOUR_REPO> is the repository name.
Add SONAR_TOKEN as a GitHub Actions secret on the repository: Settings → Secrets and variables → Actions → New repository secret. Generate the token from SonarQube Cloud under My Account → Security.
Update the CI workflow (.github/workflows/ci.yml) to run the SonarQube scan after tests. Here is a sample used by the demo app:
name: CI
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
continue-on-error: true
run: pytest -v
- name: SonarQube scan
uses: SonarSource/sonarqube-scan-action@v8
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}Three details matter here. continue-on-error: true on the test step keeps the job running when pytest fails, so the SonarQube scan executes regardless of test results. Without it, the job stops on the three test failures and SonarQube never scans. fetch-depth: 0 gives SonarQube full git history for accurate new code detection on PRs. The action references use version tags (@v4, @v5) for readability; see What to know for SHA pinning guidance.
Gitar's dashboard still shows test failures clearly, so nothing is hidden by continue-on-error.
Step 3 — Gitar GitHub App active on the repository
If you installed the Gitar GitHub App on all repositories in your organization during the quickstart, the repository is already covered. Otherwise:
- Go to app.gitar.ai and click Install
- Select the repository
- Verify that it appears in the Gitar dashboard
No configuration files are required to get started for CI failure analysis and code review. Gitar activates automatically when a PR opens or receives a push.
Leave auto-apply off for now. You'll enable it per-PR after seeing the initial analysis.
Step 4 — PR open with both tools analyzing
Push the feature branch and open a PR, which kicks off the GitHub Actions CI to run pytest (our demo had three failures, but continue-on-error lets the job continue) then the SonarQube scan step. The Gitar GitHub App receives the PR event via webhook and begins analyzing the code diff and CI logs independently.

From here, the remaining steps walk through what both tools found and how the results interact.
Step 5 — Quality gate blocked on security findings
In the demo, the SonarQube quality gate comment appeared about three minutes after the PR opened, before Gitar posted its analysis.
The quality gate fails with an E Security Rating on new code. SonarQube found three issues:
| Rule | Impact | File | Finding |
| pythonsecurity:S2083 | Security, BLOCKER | tasks.py | User-controlled data flows into file path operation |
| python:S5443 | Security, HIGH | app.py | Publicly writable /tmp directory used for exports |
| python:S6965 | Maintainability, MEDIUM | app.py | Flask route missing explicit HTTP methods parameter |
A security hotspot also fires: githubactions:S7637 flags the GitHub Actions dependencies for using version tags instead of pinned commit SHAs.


The S2083 finding traces data across two files and three function calls: request.args.get("filename") in app.py is passed as an argument to export_tasks_to_csv(), flows into os.path.join(export_dir, filename) in tasks.py, and reaches open(filepath, "w"). The analysis engine traced this through the data flow graph.
Step 6 — Four findings from two independent tools
Gitar's analysis posts shortly after SonarQube's. The dashboard comment shows four findings:
| Category | Finding |
| Bug | Pagination is 0-indexed but tests assume 1-indexed |
| Bug | sort_by_deadline sorts descending but test expects ascending |
| Security | Path traversal in export endpoint via filename parameter |
| Quality | Imports placed mid-file instead of at top |


Both tools found the path traversal independently. SonarQube detected it through taint analysis, tracing untrusted data from the Flask request parameter through os.path.join into open() and flagging it as pythonsecurity:S2083. Gitar detected the same vulnerability through LLM code review, recognizing the pattern of unsanitized user input in a file path. Different detection methods, same vulnerability, flagged within a minute of each other on the same PR, with SonarQube's detection consuming zero LLM tokens.
Gitar caught two things SonarQube didn't: the off-by-one pagination bug and the reversed sort direction. These are logic errors that no static analysis rule covers, because detecting them requires understanding what the tests expect. SonarQube caught two things Gitar didn't: the publicly writable /tmp directory (python:S5443) and the missing HTTP methods on the Flask route (python:S6965). These are deterministic findings driven by known-vulnerable patterns and framework-specific rules.
Step 7 — Automated fix pushed in one commit
Enable auto-apply by posting a comment on the PR:
gitar auto-apply:onGitar pushes a single fix commit addressing all four of its findings. In the demo, the commit landed about two and a half minutes after the command:
paginate_tasks: changedpage * page_sizeto(page - 1) * page_sizesort_by_deadline: removedreverse=Trueexport_tasks_to_csv: addedos.path.basename(filename)sanitization with aValueErrorguard- Imports moved to the top of the file



The fix commit triggers CI to re-run. Tests pass. Gitar's dashboard updates to "Approved, 4 resolved / 4 findings."
Step 8 — Green CI and AI approval, quality gate still blocked
SonarQube rescans on Gitar's fix commit. The path traversal finding (pythonsecurity:S2083) clears because Gitar's os.path.basename() fix resolved the taint flow. The Security Rating improves from E to D, but the quality gate still fails.
| Finding | Status after fix |
| pythonsecurity:S2083 — path traversal | Closed |
| python:S5443 — publicly writable /tmp directory | Open |
| python:S6965 — missing HTTP methods on route | Open |
| githubactions:S7637 — unpinned action dependencies | Unreviewed hotspot |
| 0% coverage on new code | No tests for the export endpoint |

Gitar reviewed the code, fixed every issue it found, and approved the PR. CI passes. From the AI's perspective, the PR is ready to merge.
SonarQube's quality gate blocks on issues the LLM never flagged: a publicly writable export directory, a Flask route without an explicit HTTP methods declaration, an unreviewed supply chain hotspot in the CI configuration, and zero test coverage on a new endpoint that handles user input.
Green CI and AI approval does not mean merge-ready!
How do you confirm SonarQube and Gitar are both active on a pull request?
Both layers are now active on every PR to this repository. To confirm on a new PR, push a code change to a feature branch, open a PR, and check that the SonarQube quality gate comment and Gitar's dashboard comment both appear within a few minutes.
For ongoing use, decide whether auto-apply should default to on (configure at the organization level in the Gitar dashboard at app.gitar.ai) or remain opt-in per PR via the gitar auto-apply:on comment.
The configuration files from the setup steps:
.github/workflows/ci.yml— the full workflow from Step 2, with the SonarQube scan stepsonar-project.properties— two-line config from Step 2 with your organization and project keySONAR_TOKEN— stored as a GitHub Actions secret, not committed to the repository- No Gitar configuration files needed in the repository
What to know about SonarQube & Gitar AI code review
continue-on-error: true masks test failures in CI. The GitHub Actions job reports success even when pytest fails, because the step is configured to not fail the job. Gitar's dashboard still shows test failures clearly. If your workflow needs the overall job to fail on test failures while still running the SonarQube scan, split them into separate jobs: one for tests (fails normally) and one for the scan (triggers on the same events independently).
SonarQube and Gitar do not share findings or deduplicate. If both tools find the same issue, you see it reported twice in different formats. In this demo, the path traversal appeared as SonarQube rule pythonsecurity:S2083 and as a Gitar security finding describing unsanitized user input. There is no unified view. Sonar acquired Gitar in May 2026, but these remain two independent products with no shared quality gate or dashboard. The value comes from complementary coverage, not integration.
Gitar's fixes trigger SonarQube rescans automatically. When Gitar pushes a fix commit, the CI workflow fires on the new push, the SonarQube scan step runs, and the quality gate status updates. If the fix resolves a SonarQube finding, it clears on rescan.
SonarQube Cloud's free tier supports PR decoration for pull requests targeting the main branch. Quality gate comments, issue annotations, and security hotspot reporting work with the default quality gate. Custom quality gates and PR analysis on non-main target branches require a Team plan or higher.
Pin your GitHub Actions dependencies to commit SHAs rather than version tags. The githubactions:S7637 hotspot flags actions/checkout@v4 and actions/setup-python@v5 because version tags can be re-pointed to different commits after a supply chain compromise — CVE-2025-30066 demonstrated this with the tj-actions/changed-files action. Find the full commit SHA on each action's Releases page.
Note: Gitar works with CI providers beyond GitHub Actions. This blueprint uses GitHub Actions, but Gitar's CI failure analysis also works with GitLab CI, BuildKite, CircleCI, and Bitrise. The code hosting requirement is GitHub or GitLab, but the CI pipeline can run on any supported provider.
Next steps for SonarQube and Gitar
Deterministic analysis catches what LLMs miss, and LLMs catch what deterministic analysis can't reach. Running both layers on every PR means static analysis issues get flagged at zero token cost before the LLM handles the issues that need code understanding.
- Gitar: CI analysis and fixes — multi-iteration fixing, CI retry for flaky tests, advanced configuration
- Gitar: custom review instructions — tune what Gitar looks for via
.gitar/review/*.mdfiles in your repository - SonarQube Cloud: quality gate configuration — adjust thresholds, add conditions, enforce on branches
- Sonar acquires Gitar — the strategic vision behind multilayered verification
