Step-by-step guide for pushing SCA findings into a SonarQube instance using the standalone EXE only. No IDE plugin required.
Tested with: SonarQube Community Build 26.5+ (Sonar 10+, MQR mode). SCA findings import as external issues via Generic Issue Format and appear alongside Sonar's default Sonar Way quality profile — no conflict, no override. Works with both SonarQube Server and SonarCloud.
Not covered: setting up the SonarQube server itself (Docker / creating a project / generating tokens in the web UI). Prerequisites: a running server, a user account with a token, and a project with Browse permission. If you don't have those yet, see docs/sonar-setup.md ("Troubleshooting" section) and the official SonarQube documentation.
Official source: https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/
Direct downloads (Windows x64): https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/
PowerShell quick-install:
# Adjust version as needed
$ver = "6.2.1.4610"
Invoke-WebRequest `
"https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$ver-windows-x64.zip" `
-OutFile "$env:TEMP\sonar-scanner.zip"
Expand-Archive "$env:TEMP\sonar-scanner.zip" -DestinationPath C:\Tools -Force
Rename-Item "C:\Tools\sonar-scanner-$ver-windows-x64" "C:\Tools\sonar-scanner"
# Add to user PATH (persistent)
[Environment]::SetEnvironmentVariable("PATH",
"$env:PATH;C:\Tools\sonar-scanner\bin", "User")Open a new PowerShell window so the PATH change takes effect, then verify:
sonar-scanner --versionShould print something like INFO: SonarScanner CLI 6.2.1.4610. Since
version 5 the scanner ships a bundled JRE — no separate Java install needed.
Open StaticCodeAnalyserForm/StaticCodeAnalyser.d12.dproj in Delphi 12,
switch to Win32 / Release, Build.
Result: StaticCodeAnalyserForm\Win32\Release\StaticCodeAnalyser.d12.exe.
rules\sca-rules.json is the data source for the per-rule
cleanCodeAttribute and impacts fields (Sonar MQR mode). By default the
EXE looks for the catalog relative to its own location. If you plan to run
scans from arbitrary working directories later on, drop a user copy so the
EXE always finds it:
$dst = "$env:APPDATA\StaticCodeAnalyser\rules"
New-Item -ItemType Directory -Force $dst | Out-Null
Copy-Item "D:\git-demos\delphi\StaticCodeAnalyser\rules\sca-rules.json" `
"$dst\sca-rules.json" -ForceAfter catalog updates in the repo: re-copy. (See docs/sonar-config.md for the full lookup order.)
You have three ways to give the EXE the connection details — pick one, don't mix:
analyser.exe --sonar-test `
--sonar-host http://sonar.company.com:9000 `
--sonar-token squ_xxxxxxxxxx `
--sonar-project my-delphi-projectFast for tests / CI pipelines. Caveat: the token ends up in shell history.
$env:SONAR_HOST_URL = "http://sonar.company.com:9000"
$env:SONAR_TOKEN = "squ_xxxxxxxxxx"
$env:SONAR_PROJECT_KEY = "my-delphi-project"
analyser.exe --sonar-testRecommended for CI (secret stores supply the variables).
Persistent per local Windows user, token DPAPI-encrypted:
analyser.exe --sonar-host http://sonar.company.com:9000 `
--sonar-project my-delphi-project `
--sonar-token squ_xxxxxxxxxx `
--sonar-testOn first call — if the file doesn't exist yet — the EXE creates
%APPDATA%\StaticCodeAnalyser\analyser.ini with the [Sonar] section plus
the encrypted token under [SonarTokens]. Subsequent runs need no flags:
analyser.exe --sonar-testThe token can only be decrypted by the same Windows user on the same machine.
analyser.exe --sonar-testExpected output (all four stages green):
Sonar config:
host = http://sonar.company.com:9000 (CLI --sonar-host)
project = my-delphi-project (analyser.ini)
token = (42 chars from CLI --sonar-token)
[OK] DNS resolution: sonar.company.com -> 10.0.0.42
[OK] HTTP /api/system/status: UP
[OK] Token validation: valid
[OK] Project access: my-delphi-project (visible)
Sonar connection healthy.
On failure: the [FAIL] line states the cause (DNS, server status, token,
or project permission).
cd D:\path\to\your\repo
analyser.exe --sonar-initWrites a template into sonar-project.properties — edit:
sonar.projectKey=my-delphi-project
sonar.projectName=My Delphi Project
sonar.sources=.
sonar.sourceEncoding=UTF-8
sonar.exclusions=**/*.dcu,**/*.bpl,**/lib/**,**/Win32/**,**/Win64/**
sonar.externalIssuesReportPaths=sca-findings.jsonThis file is committed to VCS (the token does not belong in it — it comes at runtime via env var or DPAPI INI).
Alternative: pass every value via -D on each call (see step 4 below). Then
no sonar-project.properties is needed.
analyser.exe `
--path D:\path\to\your\repo `
--full `
--base-dir D:\path\to\your\repo `
--sonar-export D:\path\to\your\repo\sca-findings.jsonKey points:
--full= recursive scan (branch mode would be--branch— only VCS-changed files)--base-dirensures the file paths in the JSON are relative to the repo root, not absolute. Otherwise Sonar can't link findings to source files--sonar-export <file>writes the Sonar Generic Issue Format JSON- Optional:
--quietsuppresses the per-finding stdout (only the summary at the end)
Final line of output:
Sonar Generic report written: D:\path\to\your\repo\sca-findings.json
Findings: 529 (Errors: 18, Warnings: 30, Hints: 481)
$env:SONAR_TOKEN = "squ_xxxxxxxxxx"
cd D:\path\to\your\repo
sonar-scannerThe scanner reads sonar-project.properties automatically.
$env:SONAR_TOKEN = "squ_xxxxxxxxxx"
cd D:\path\to\your\repo
sonar-scanner `
"-Dsonar.host.url=http://sonar.company.com:9000" `
"-Dsonar.projectKey=my-delphi-project" `
"-Dsonar.projectName=My Delphi Project" `
"-Dsonar.sources=." `
"-Dsonar.sourceEncoding=UTF-8" `
"-Dsonar.exclusions=**/*.dcu,**/*.bpl,**/lib/**,**/Win32/**,**/Win64/**" `
"-Dsonar.externalIssuesReportPaths=sca-findings.json"Successful output ends with:
INFO ANALYSIS SUCCESSFUL, you can find the results at:
http://sonar.company.com:9000/dashboard?id=my-delphi-project
INFO EXECUTION SUCCESS
INFO Total time: 22.081s
First run is slower (Sonar downloads language plugins). Subsequent runs ~10–30 s depending on file count.
Save as push-to-sonar.ps1 in the repo root and run it as a task or
manually:
# push-to-sonar.ps1
$ErrorActionPreference = "Stop"
$exe = "D:\git-demos\delphi\StaticCodeAnalyser\StaticCodeAnalyserForm\Win32\Release\StaticCodeAnalyser.d12.exe"
$repo = $PSScriptRoot
$json = Join-Path $repo "sca-findings.json"
# Load DPAPI-encrypted token from analyser.ini
Add-Type -AssemblyName System.Security
$ini = Get-Content "$env:APPDATA\StaticCodeAnalyser\analyser.ini" -Raw -Encoding UTF8
$tokenHex = ([regex]::Match($ini, '(?m)^ide-default=(.+)$')).Groups[1].Value.Trim()
$bytes = [byte[]]::new($tokenHex.Length / 2)
for ($i = 0; $i -lt $tokenHex.Length; $i += 2) {
$bytes[$i / 2] = [Convert]::ToByte($tokenHex.Substring($i, 2), 16)
}
$env:SONAR_TOKEN = [System.Text.Encoding]::UTF8.GetString(
[System.Security.Cryptography.ProtectedData]::Unprotect(
$bytes, $null, "CurrentUser"))
try {
# 1. Analyze + export
& $exe --path $repo --full --base-dir $repo --sonar-export $json --quiet
if ($LASTEXITCODE -ge 99) { throw "SCA failed (exit $LASTEXITCODE)" }
# 2. Push
Push-Location $repo
try {
& sonar-scanner # reads sonar-project.properties
if ($LASTEXITCODE -ne 0) { throw "sonar-scanner failed (exit $LASTEXITCODE)" }
} finally {
Pop-Location
}
} finally {
Remove-Item Env:SONAR_TOKEN -ErrorAction SilentlyContinue
}| Symptom | Cause | Fix |
|---|---|---|
[FAIL] DNS resolution |
Host unreachable, URL typo | Check URL, ping host |
[FAIL] HTTP /api/system/status: 503 |
Server still booting | Wait ~60 s, retry |
[FAIL] Token validation: 401 |
Token invalid / expired | Generate a new token in Sonar |
[FAIL] Project access: not found |
Project doesn't exist | Create in Sonar (Web UI) |
[FAIL] Project access: 403 (project exists) |
Missing Browse permission | Project Permissions → grant Browse |
Failed to parse report: either type, impacts or both should be provided |
Stale standalone EXE without catalog | Rebuild EXE (0.2), deploy catalog to APPDATA (0.3) |
| Issues missing in Sonar | Wrong --base-dir → absolute paths |
Set --base-dir equal to --path |
sonar-scanner not found |
PATH not active | Open a new shell window |
| Files appear "Empty" in Sonar | sonar.exclusions too broad |
Review sonar.exclusions in properties |
- docs/sonar-setup.md — full setup guide (incl. IDE plugin and CI examples)
- docs/sonar-config.md — resolver order (CLI > Env > Properties > INI)
- Sonar Scanner documentation
- Sonar Generic Issue Format