Skip to content
Back to skills

Sonar Onboard

ASecurity

Scaffold a repo for Sonar compliance — supports both **SonarQube server** (self-hosted) and **SonarCloud** (SaaS), user picks at setup time. Generates `sonar-project.properties` with language-correct source/test/coverage paths, a CI workflow that runs the scanner on every push and PR and blocks merge on quality-gate failure, and a README snippet documenting the gate. One-shot setup; pair with `sonar-review` for per-change feedback. Use when the user says "set up Sonar", "add SonarQube to this...

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsjavascripttypescriptpythonrustgojavarubyphpkotlinc#

Works with

  • api

Security analysis

A100/100

Pro scans all 9 files and shows the line behind each finding

Scanned September 19, 2026

npx -y skills add sananthanarayan/skilldrop --skill sonar-onboard --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sonar Onboard?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sonar Onboard
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sananthanarayan-sonar-onboard/badge)](https://www.skillsdirectory.com/skills/sananthanarayan-sonar-onboard)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sonar-onboard
description: Scaffold a repo for Sonar compliance — supports both **SonarQube server** (self-hosted) and **SonarCloud** (SaaS), user picks at setup time. Generates `sonar-project.properties` with language-correct source/test/coverage paths, a CI workflow that runs the scanner on every push and PR and blocks merge on quality-gate failure, and a README snippet documenting the gate. One-shot setup; pair with `sonar-review` for per-change feedback. Use when the user says "set up Sonar", "add SonarQube to this repo", "wire up SonarCloud", "set up the quality gate", or asks to make a project Sonar-compliant for the first time.
---

# sonar-onboard

Scaffolds the artifacts a repo needs to become Sonar-compliant: a `sonar-project.properties` keyed to the project's actual language and layout, a CI workflow that runs the scanner and enforces the quality gate, and a README block so the next contributor knows what the gate means and how to run a scan locally.

This is a **one-shot setup skill**. For per-change feedback after the repo is onboarded, use [`sonar-review`](../sonar-review/SKILL.md).

Supports both deployment models — the user picks one:

| Mode | When it's right | Host | Key extras |
|---|---|---|---|
| **SonarQube server** | Self-hosted, on-prem or in own VPC. Enterprise / regulated orgs. | `https://sonar.<company>.com` (set per-org) | Project token + host URL |
| **SonarCloud** | SaaS, hosted by SonarSource. Faster setup, no infra. | `https://sonarcloud.io` (fixed) | Project token + **organization key** |

The choice changes three things: the properties file (SonarCloud needs `sonar.organization`), the GitHub Actions step (different action), and the secrets the user must add. Everything else is identical.

## How to respond

1. **Ask which mode** if the user hasn't said — it's the first question. One question, not two:

   > Which Sonar are you using — **SonarQube server** (self-hosted) or **SonarCloud** (SaaS at sonarcloud.io)?

   If they describe the host URL, infer: anything matching `sonarcloud.io` ⇒ SonarCloud; anything else ⇒ SonarQube server. Don't ask twice.

2. **Collect the inputs.** Ask for whichever are missing. Cap at two more clarifying questions per turn; pick defaults for the rest and call them out:

   | Input | Required for | Default if not given |
   |---|---|---|
   | **Project key** (e.g. `myorg_payments-api`) | both | `<repo-name>` (derive from `git remote get-url origin`) |
   | **Organization key** (SonarCloud only, e.g. `my-org`) | SonarCloud | Required — ask if missing |
   | **SonarQube host URL** (e.g. `https://sonar.company.com`) | SonarQube server | Required — ask if missing |
   | **Primary language(s)** | both | Detect from repo (see step 3) |
   | **CI system** | both | GitHub Actions (emit `gitlab-ci`/`jenkins`/`azure-pipelines` only if user names it) |
   | **Coverage tool** | both | Detect from language (see step 4) |

3. **Detect language(s)** from the working tree — don't ask if a probe will tell you:

   | Marker file | Language | Default source dir |
   |---|---|---|
   | `package.json` | JavaScript / TypeScript | `src` |
   | `pom.xml` | Java (Maven) | `src/main/java` |
   | `build.gradle` / `build.gradle.kts` | Java / Kotlin (Gradle) | `src/main/java` or `src/main/kotlin` |
   | `requirements.txt` / `pyproject.toml` / `setup.py` | Python | top-level package dir or `src` |
   | `go.mod` | Go | repo root |
   | `*.csproj` / `*.sln` | C# / .NET | project dirs |
   | `Cargo.toml` | Rust | `src` |
   | `composer.json` | PHP | `src` |
   | `Gemfile` | Ruby | `lib` and `app` |

   Multi-language is normal (e.g. TypeScript frontend + Python backend) — set `sonar.sources` to a comma-separated list and emit one combined `sonar-project.properties`. Don't generate one file per language.

4. **Pick the coverage report path** based on language. These are the formats Sonar's importers expect:

   | Language | Coverage report | Sonar property |
   |---|---|---|
   | JS / TS | `coverage/lcov.info` (Jest, Vitest default) | `sonar.javascript.lcov.reportPaths` |
   | Java (Maven) | `target/site/jacoco/jacoco.xml` | `sonar.coverage.jacoco.xmlReportPaths` |
   | Java (Gradle) | `build/reports/jacoco/test/jacocoTestReport.xml` | `sonar.coverage.jacoco.xmlReportPaths` |
   | Python | `coverage.xml` (`pytest-cov --cov-report=xml`) | `sonar.python.coverage.reportPaths` |
   | Go | `coverage.out` | `sonar.go.coverage.reportPaths` |
   | C# | `coverage.opencover.xml` (coverlet) | `sonar.cs.opencover.reportsPaths` |

   If the user has no coverage tool today, **don't fabricate a report path**. Omit the coverage property and add a `# TODO` comment in the properties file pointing them at the right one.

5. **Generate `sonar-project.properties`** using [`templates/sonar-project.properties.tmpl`](templates/sonar-project.properties.tmpl). Fill placeholders; remove blocks that don't apply.

   **For SonarCloud**, add this line (immediately after `sonar.projectKey`):
   ```
   sonar.organization={{ORG_KEY}}
   ```
   The organization key is mandatory for SonarCloud and rejected by SonarQube server — emit it for one and not the other.

   **Exclusions** — add these by default; they save the next contributor from a noisy first scan:
   ```
   sonar.exclusions=**/node_modules/**,**/dist/**,**/build/**,**/.next/**,**/__pycache__/**,**/*.generated.*,**/vendor/**,**/migrations/**
   sonar.test.exclusions=**/*.test.*,**/*.spec.*,**/test/**,**/tests/**
   sonar.coverage.exclusions=**/*.test.*,**/*.spec.*,**/test/**,**/tests/**,**/*.stories.*,**/index.{js,ts}
   ```
   Trim language-irrelevant entries (e.g. drop `__pycache__` for a pure-JS repo).

6. **Generate the CI workflow.** Default is GitHub Actions. Pick the template by mode:

   | Mode | Template | Scan action | Gate action |
   |---|---|---|---|
   | SonarQube server | [`templates/github-actions-sonar-server.yml.tmpl`](templates/github-actions-sonar-server.yml.tmpl) | `sonarsource/sonarqube-scan-action@v3` | `sonarsource/sonarqube-quality-gate-action@master` |
   | SonarCloud | [`templates/github-actions-sonarcloud.yml.tmpl`](templates/github-actions-sonarcloud.yml.tmpl) | `SonarSource/sonarcloud-github-action@master` | (built into scan action — `pollingTimeoutSec` controls wait) |

   Both must:
   - Trigger on `push` to default branch **and** `pull_request` (Sonar needs the PR event to comment on the PR).
   - Use `actions/checkout@v4` with `fetch-depth: 0` (Sonar needs full history to attribute blame).
   - Run the project's build + test + coverage **before** the scanner, otherwise coverage is empty.
   - Reference `SONAR_TOKEN` from GitHub Secrets — never inline.

   Mode-specific:
   - **Server** also references `SONAR_HOST_URL` from Secrets, and runs a separate `sonarqube-quality-gate-action` step so the job fails on gate failure.
   - **SonarCloud** doesn't need `SONAR_HOST_URL` (the action defaults to `https://sonarcloud.io`), and references `GITHUB_TOKEN` for PR decoration.

   For GitLab / Jenkins / Azure DevOps, see [`reference.md`](reference.md) — only emit those if the user names them.

7. **Generate the README snippet** using [`templates/readme-snippet.md`](templates/readme-snippet.md). Drop it under a `## Code quality` heading. It documents: what the gate enforces, the two required secrets, the local-scan command, and where to read findings (Sonar UI link).

8. **List the secrets the user must add manually.** End your response with this exact block — the skill cannot set secrets and shouldn't pretend it can. The steps differ by mode:

   **SonarQube server:**
   ```
   Manual steps you must do before the workflow runs green:
   1. Create a SonarQube project at <SONAR_HOST_URL>/projects/create with key `<project-key>`.
   2. Generate a project token (My Account → Security → Generate Token).
   3. Add GitHub Secret `SONAR_TOKEN` with the token value.
   4. Add GitHub Secret `SONAR_HOST_URL` with `<SONAR_HOST_URL>`.
   5. (Optional) Tighten the Quality Gate in Sonar UI — defaults are listed in the README snippet.
   ```

   **SonarCloud:**
   ```
   Manual steps you must do before the workflow runs green:
   1. Sign in at https://sonarcloud.io with the GitHub account that owns this repo.
   2. Create / import the project: + → Analyze new project → pick the repo. Confirm organization is `<org-key>` and project key is `<project-key>`.
   3. Disable "Automatic Analysis" on the project (Administration → Analysis Method) — the CI-driven scan and Automatic Analysis cannot both run.
   4. Generate a token (My Account → Security → Generate Token).
   5. Add GitHub Secret `SONAR_TOKEN` with the token value.
   6. (Optional) Tighten the Quality Gate in SonarCloud UI — defaults are listed in the README snippet.
   ```

## Useful references in this skill

- [`templates/sonar-project.properties.tmpl`](templates/sonar-project.properties.tmpl) — properties file skeleton (works for both modes; `sonar.organization` line is SonarCloud-only)
- [`templates/github-actions-sonar-server.yml.tmpl`](templates/github-actions-sonar-server.yml.tmpl) — CI workflow for self-hosted SonarQube
- [`templates/github-actions-sonarcloud.yml.tmpl`](templates/github-actions-sonarcloud.yml.tmpl) — CI workflow for SonarCloud
- [`templates/readme-snippet.md`](templates/readme-snippet.md) — README section for the gate (mode-aware placeholders)
- [`reference.md`](reference.md) — GitLab / Jenkins / Azure DevOps variants, quality-gate tuning, monorepo guidance, server vs cloud differences

## Quality bar

- **Properties file is keyed to the actual repo.** `sonar.projectKey`, `sonar.sources`, `sonar.tests`, and the coverage path must reflect what's on disk — not a generic example. A properties file that scans the wrong directories produces a green gate that means nothing.
- **The workflow blocks merge on gate failure.** A scan that runs but doesn't fail PRs is decoration. The `sonarqube-quality-gate-action` step is non-negotiable.
- **Coverage path exists or is marked TODO.** Pointing at a coverage file that the test step never produces gives Sonar 0% coverage and a false-failing gate. Either wire it up end-to-end or leave it explicit.
- **`fetch-depth: 0` in checkout.** Shallow clones break Sonar's new-code-period detection. The first scan will look fine; the next ten PRs will mis-attribute issues.
- **Secrets are referenced, never inlined.** No raw tokens or URLs in committed files. The token belongs in GitHub Secrets; the URL too, even though it's not technically secret — it keeps fork PRs from leaking the host.
- **README snippet tells the next contributor what the gate enforces.** "Sonar must pass" is not enough — list the conditions (no new bugs, no new vulnerabilities, coverage on new code ≥ X%, duplication ≤ Y%).

## When to use this skill

- ✅ First-time Sonar setup on a repo (server or cloud)
- ✅ Migrating between modes — SonarCloud → self-hosted (or vice versa). Re-scaffold with the new mode; remember to switch templates *and* the properties file.
- ✅ Adding Sonar to a fork or a new service in a monorepo (one properties file per module — see `reference.md`)
- ✅ Replacing an ad-hoc, locally-run scanner setup with a gate-enforcing CI workflow

## When NOT to use this skill

- ❌ Repo already has a working `sonar-project.properties` and a CI workflow that runs the scanner. Use `sonar-review` for per-change feedback instead.
- ❌ User wants to disable rules or relax the gate to make a failing scan pass. That's a code-quality conversation, not a setup task — push back.
- ❌ User wants language-specific deep config (custom rule profiles, Sonar plugins, branch analysis tuning). Out of scope; point at [`reference.md`](reference.md) and the Sonar docs.
- ❌ User wants both SonarQube server *and* SonarCloud scanning the same repo. Pick one — running both means two gates, two histories, and two answers to "did the build pass?".

## Anti-patterns to avoid

- ❌ **Emitting `sonar.organization` for SonarQube server.** It's SonarCloud-only and the server rejects it. Conversely: omitting it for SonarCloud breaks the scan.
- ❌ **Emitting a `sonar.login=...` line.** Deprecated since Sonar 10. Use `SONAR_TOKEN` env var, which both scan actions read automatically.
- ❌ **Hard-coding the host URL in the properties file** (server mode). It belongs in CI env / the scan action input, so forks and local runs don't ship someone else's Sonar.
- ❌ **Forgetting to disable SonarCloud's Automatic Analysis.** The CI scan and Automatic Analysis can't coexist; SonarCloud will fail one of them. The Manual Steps block must include this — it's the #1 cause of "scan ran but didn't update".
- ❌ **Generating multiple `sonar-project.properties` files for a multi-language single project.** One project = one properties file with comma-separated `sonar.sources`.
- ❌ **Skipping `pull_request` trigger.** A scan that only runs on `main` finds problems after they're merged — defeats the purpose.
- ❌ **Inventing a coverage path because "Sonar wants one".** If the project doesn't generate coverage, omit the property and TODO it. A path that points at nothing produces a misleading gate.
- ❌ **Recommending the user disable rules to pass the gate.** The gate exists to surface real issues. Suggest fixes or scope the gate to "new code" rather than turning rules off.
- ❌ **Burying the manual steps.** The "Manual steps you must do" block is the most important output — the workflow can't run green without it. Don't summarize it; print it verbatim.

Files in this skill

  • SKILL.md13.3 KB
  • evals/eval_queries.json801 B
  • evals/evals.json784 B
  • manifest.json1.1 KB
  • reference.md7.1 KB
  • templates/github-actions-sonar-server.yml.tmpl2.1 KB
  • templates/github-actions-sonarcloud.yml.tmpl2.3 KB
  • templates/readme-snippet.md1.5 KB
  • templates/sonar-project.properties.tmpl1.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.