Testland
Browse all skills & agents

sonarqube-rules

Configures and runs SonarQube / SonarCloud - multi-language SAST + Quality Gate platform with built-in Sonar Way rule profiles + custom rule plugins; integrates `sonar-scanner` with `sonar-project.properties` config; supports Quality Gate definitions including new-code-period blocking, branch + PR analysis, and per-issue suppression via `// NOSONAR` comment or `@SuppressWarnings("squid:RULE_ID")` annotation. Use when the user runs SonarQube Community / Developer / Enterprise edition or SonarCloud, or needs a multi-language SAST + code-quality platform with persistent issue tracking.

Install with skills.sh (any agent)

npx skills add testland/qa --skill sonarqube-rules
View source

sonarqube-rules

Overview

Per github.com/SonarSource/sonarqube (opens in new window):

"SonarQube provides the capability to not only show the health of an application but also to highlight issues newly introduced."

The platform's distinguishing features vs Semgrep / CodeQL:

  • Quality Gate - pass/fail decision based on configurable threshold conditions (coverage on new code, duplication, security hotspots reviewed, maintainability rating, etc.).
  • New-code-period - issues are categorized as "new code" vs "overall code"; gates focus on new-code metrics so legacy debt doesn't block deploys.
  • Persistent issue tracking - server-side storage of issues across scans; status workflow (open / confirmed / resolved / false positive / won't fix).
  • Cross-language coverage - 30+ languages with one tool + unified UI.

When to use

  • Existing SonarQube deployment (Community / Developer / Enterprise / SonarCloud).
  • The team needs persistent issue tracking + Quality Gate workflow.
  • Multi-language coverage in one platform is a requirement.
  • New-code-period gating fits the team's deploy cadence.

For new projects without a SonarQube investment, evaluate semgrep-rules (lower friction; no server) first.

Step 1 - Install (server side)

Per docs.sonarsource.com/sonarqube-server (opens in new window):

Docker (most common for evaluation):

docker run -d --name sonarqube \
  -p 9000:9000 \
  sonarqube:lts-community

For production, consult sq-docs (opens in new window) for Postgres + JVM sizing + reverse-proxy configuration. Default admin: admin / admin (change immediately).

Step 2 - sonar-scanner CLI

Download from docs.sonarsource.com/sonarqube-server (opens in new window) "Analysis scanners". Place on PATH.

sonar-scanner \
  -Dsonar.projectKey=my-project \
  -Dsonar.sources=. \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.token=$SONAR_TOKEN

For Maven / Gradle / .NET, use the language-native scanner plugin (mvn sonar:sonar / ./gradlew sonar / dotnet sonarscanner).

Step 3 - sonar-project.properties config

Project-root file replaces -D flags:

# sonar-project.properties
sonar.projectKey=my-project
sonar.projectName=My Project
sonar.sources=src
sonar.tests=tests
sonar.exclusions=**/*.spec.ts,**/generated/**
sonar.sourceEncoding=UTF-8

# Coverage from external tool (Jest, JaCoCo, etc.)
sonar.javascript.lcov.reportPaths=coverage/lcov.info

# New-code-period (analysis scope)
sonar.newCode.referenceBranch=main

# Quality Gate (referenced by ID; created via UI/API)
sonar.qualitygate.wait=true

sonar.qualitygate.wait=true makes the scanner block until the gate decision is computed - critical for CI gating.

Step 4 - Quality Gate concept

The default "Sonar Way" gate enforces (consult your SonarQube UI at Quality Gates → Sonar Way for current conditions):

  • Coverage on New Code ≥ X%
  • Duplicated Lines on New Code ≤ Y%
  • Maintainability Rating on New Code = A
  • Reliability Rating on New Code = A
  • Security Rating on New Code = A
  • Security Hotspots on New Code reviewed = 100%

Custom gates can be defined via UI or REST API (/api/qualitygates/create).

Step 5 - Branch + PR analysis

For PR analysis (Developer edition+):

sonar-scanner \
  -Dsonar.pullrequest.key=$PR_NUMBER \
  -Dsonar.pullrequest.branch=$PR_BRANCH \
  -Dsonar.pullrequest.base=main

PR results post as comments to GitHub / GitLab / Bitbucket per the integration setup in SonarQube admin.

Step 6 - False-positive triage (MANDATORY)

Three suppression layers in priority order:

MechanismExampleWhen to use
Per-line NOSONARint x = 0; // NOSONAR justification textSingle-line exception with inline reason
Annotation@SuppressWarnings("squid:S106")Java/Kotlin per-block exception
Server-side mark-as-FPUI: Issues → Resolve as False PositivePersistent across scans; auditable
Server-side mark-as-Won't FixUI: Issues → Resolve as Won't FixAcknowledged risk; not a defect

Justification template (mandatory in code):

// NOSONAR squid:S106 - Reason: required for CLI tool stdout output
// Reviewer: alice@example.com (2026-05-15)
// Expires: 2026-12-15
System.out.println(message);

Server-side resolution requires a comment per SonarQube workflow config - make it mandatory in admin settings (Administration → Configuration → Issues → Comment required to set status).

Cadence: Issues → False Positive filter periodically; review for expiration. Server-side resolutions are persistent and auditable - the audit trail is the value over Semgrep's per-comment approach.

Step 7 - CI integration

jobs:
  sonarqube:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with: { fetch-depth: 0 }   # full history needed for new-code-period
      - uses: SonarSource/sonarqube-scan-action@v5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
      - uses: SonarSource/sonarqube-quality-gate-action@v1
        timeout-minutes: 5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

fetch-depth: 0 is critical - without full git history, new-code-period detection is broken.

Step 8 - REST API integration

For automation / dashboards:

EndpointUse
GET /api/issues/search?projectKeys=...Issue list with filters
GET /api/qualitygates/project_statusCurrent gate verdict
POST /api/issues/do_transitionMark FP / Won't Fix
GET /api/measures/component_treePer-file metrics

API token via User → My Account → Security → Generate Tokens.

Anti-patterns

Anti-patternWhy it failsFix
fetch-depth: 1 in CINew-code-period broken; gates produce wrong decisionsAlways fetch-depth: 0 (Step 7)
Skip sonar.qualitygate.waitCI exits before gate evaluates; missed regressionssonar.qualitygate.wait=true (Step 3)
NOSONAR without justificationServer-side audit trail emptyRequired template (Step 6)
Custom Quality Gate without team buy-inGate fails on PRs no one understandsDocument gate definition; reference in PR template
Mass-resolve as FP without reviewBackdoor for skipping security findingsRequire comment + reviewer attribution (Step 6)

Limitations

  • SonarQube server requires hosting + maintenance; SonarCloud is the SaaS alternative.
  • Branch + PR analysis are Developer-edition+ features - Community edition only supports main branch.
  • Some language-specific deep-rule features require Developer or Enterprise edition.
  • New-code-period requires accurate git history; shallow clones break it.
  • License changed from LGPL to SSPL in 2024 - verify license compatibility for commercial use.

References

  • sq-gh (opens in new window) - repository
  • sq-docs (opens in new window) - official SonarQube documentation root
  • docs.sonarsource.com/sonarqube-server/latest/user-guide/quality-gates - Quality Gates user guide
  • docs.sonarsource.com/sonarqube-server/latest/user-guide/issues - Issue workflow + transitions
  • semgrep-rules, codeql-queries, bandit-python, gosec-go - sister scanners

Related skills

bandit-python

Configures and runs Bandit - Python-only SAST covering 60+ rule IDs across 7 categories (B1xx-B7xx: misc, app, crypto, imports, injections, XSS); `bandit -r .` scan, `--severity-level` + `--confidence-level` filtering, `# nosec`/`# nosec B404` per-line and per-rule suppression, `pyproject.toml [tool.bandit]` config. Use for a focused, low-overhead Python SAST in pre-commit / CI. Python-only: for Go use gosec-go, for cross-language pattern SAST use semgrep-rules; to merge Bandit findings with other scanners into one gate use multi-tool-finding-triage - not this for non-Python code.

codeql-queries

Configures and runs GitHub CodeQL - semantic-database SAST with queries written in the CodeQL declarative query language; supports `codeql database create` (per-language) + `codeql database analyze` with --format=sarif; ships query packs (`codeql/javascript-queries`, `codeql/python-queries`, `codeql/java-queries`, `codeql/go-queries`, etc.); integrates with GitHub Code Scanning via SARIF upload; suppression via inline comment + sarif-filter + Security-tab dismissal. Use when the team uses GitHub-hosted repos and needs deep semantic SAST beyond pattern matching (cross-file taint flows, dataflow analysis).

eslint-security-rules

Configures and runs `eslint-plugin-security` (14 detect-* rules covering injection, path traversal, ReDoS, unsafe buffers, and bidi trojan-source) plus `eslint-plugin-no-unsanitized` (DOM XSS via `innerHTML`, `outerHTML`, `document.write`, `insertAdjacentHTML`) as the JS/TS first-party SAST layer; covers flat config setup, per-rule suppression with justification templates, SARIF output via `@microsoft/eslint-formatter-sarif` for GitHub Code Scanning upload, and CI gating on ESLint exit code 1. Use when the project is JS or TS and needs an in-process security lint pass without a separate SAST server.

gosec-go

Configures and runs gosec - Go-only SAST covering 40+ rule IDs (G101 hardcoded creds, G104 unhandled errors, G304 path traversal, G401 weak crypto, G601 memory aliasing) via Go AST + SSA taint tracking; `gosec ./...` scan, `#nosec G404 -- justification` suppression, `--fmt sarif|json|junit-xml|html`, golangci-lint integration. Use for a focused Go SAST wired into golangci-lint / CI. Go-only: for Python use bandit-python, for cross-language pattern SAST use semgrep-rules; to merge gosec findings with other scanners into one gate use multi-tool-finding-triage - not this for non-Go code.

multi-tool-finding-triage

Merges two or more security scanner reports into one gate. Use when you need a single BLOCK or PASS decision from multiple scanners instead of reading N separate reports. Normalizes each report into one common finding format (a canonical `Finding`), deduplicates on a per-domain key while recording which scanners agree (`caught_by` consensus), validates a waiver (finding-suppression) file, rejecting any missing `expires:` / `approved_by:` / `reason:` or expired, enriches CVE findings with EPSS (exploit-probability) and CISA KEV (known-exploited catalog), then applies a `fail_on` severity threshold to emit BLOCK or PASS plus a bucketed pull-request comment. Works across static (SAST), dynamic (DAST), secret, dependency (SCA), container, and IaC scanners. To run a single scanner instead use semgrep-rules, codeql-queries, bandit-python, or gosec-go; this runs after them to merge output - the cross-scanner gate, not a single-scanner wrapper.

pmd-apex-rules

Runs PMD's built-in Apex security ruleset (`category/apex/security.xml`) against Salesforce Apex source to detect injection, privilege-escalation, cryptographic, and XSS vulnerabilities; configures custom rulesets for regulated-industry Apex codebases; emits SARIF for GitHub Code Scanning upload; integrates `pmd check` as a PR-blocking CI gate. Use when the codebase contains Salesforce Apex and the team needs SAST coverage for ApexSOQLInjection, ApexCRUDViolation, ApexSharingViolations, or the full 10-rule security category.

semgrep-rules

Configures and runs Semgrep - pattern-based SAST across 30+ languages with the Semgrep Registry rulesets (`p/owasp-top-ten`, `p/default`, `auto`) plus custom YAML rules; integrates `semgrep ci` for PR-blocking gates with `--baseline-commit` diff-aware scanning, per-finding inline `nosemgrep` suppressions, `--exclude` / `--include` path filters, output formats (`--json` / `--sarif` / `--gitlab-sast` / `--junit-xml`), and severity filter (INFO/WARNING/ERROR). Use when the user runs Semgrep, asks about pattern rules, or needs a low-friction SAST gate without semantic-DB setup.