Share a SonarQube report

SonarQube's problem is not the analysis. It is that the analysis lives at https://sonar.internal:9000 behind a login, and the people who most need to see a finding — the contractor finishing the module, the security reviewer doing a one-off pass, the manager asking whether the debt is going down — are exactly the people without an account.

So findings get screenshotted, and the quality gate becomes a red or green dot in a PR with no readable detail behind it.

First: get an HTML report out of it

SonarQube itself doesn't emit one. Its built-in issues report was removed long ago, and what remains is the web UI and the JSON web API. Two generators are in common use, both of which read that API and write a self-contained HTML file:

# sonar-report (npm)
npx sonar-report \
  --sonarurl="$SONAR_HOST_URL" \
  --sonarcomponent="$SONAR_PROJECT_KEY" \
  --sonartoken="$SONAR_TOKEN" \
  --branch="$(git rev-parse --abbrev-ref HEAD)" \
  --output sonar-report.html

The CNES report generator (a JAR, widely used in regulated environments) produces the same shape plus a spreadsheet and a document export. Either way you end up with one HTML file — which is the shape that publishes in a single call.

Then: publish it

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html sonar-report.html \
        --arg title "Sonar — $(git rev-parse --short HEAD)" \
        '{title: $title, html: $html}')"

Use a scoped token (reports:write) from CI secrets, and PATCH a saved report id rather than POSTing — that keeps one URL per project with a revision per scan, instead of a new orphan link every build. See publishing from CI.

Make the step unconditional (if: always() in GitHub Actions, post { always { … } } in Jenkins). A failed quality gate is precisely when someone wants to read the report.

Access without seats

Sonar access is a server account. Report access is per report: private, your team, anyone signed in at your domain, or anyone with the link, with view / comment / edit rights for link holders. See sharing & access control.

That difference is the point. Handing an auditor a read-only URL for one scan is a very different decision from handing them a login to the server that holds every project's source-level findings.

Argue with the findings, in place

Static analysis findings are a conversation, not a verdict. A meaningful share of them are false positives, rule misconfigurations, or genuinely intentional code. Published to a URL, that conversation happens on the finding: select it, leave a thread, and it stays anchored there across scans — so the next person who trips the same rule finds the reasoning instead of re-deriving it. See commenting on HTML.

Revision diffs answer the other recurring question honestly. Two revisions, one diff, and you can see which findings actually cleared rather than trusting a trend chart.

Limits

  • Entry HTML: 5 MB. A large project's full issue list can exceed that — scope the generator to new code or to blocker/critical severities, which is the report people read anyway. Assets: 25 MB per file, 250 MB and 500 files total.
  • Scripts run, sandboxed (allow-scripts, no allow-same-origin), so the report's own filtering and sorting keeps working.
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish a Sonar report →

Related