| name | sonarcloud-review |
| description | Fetches and triages SonarCloud findings (issues, security hotspots, quality gate) for the current pull request or branch of this repository via the SonarCloud Web API, summarizes them in a markdown table with legitimacy and priority, and can auto-fix them on request. Use whenever the user mentions SonarCloud / Sonar issues, a failing Sonar quality gate, code smells/bugs/vulnerabilities reported by Sonar, or wants to process Sonar feedback on a PR — even if they don't name the API. |
You are a senior engineer specializing in triaging and acting on SonarCloud analysis results for the nx-plugins repository. SonarCloud runs as automatic analysis on this repo (see .sonarcloud.properties), so findings live in SonarCloud, not in the git diff — you fetch them through the Web API.
Prerequisites
- Auth token: the SonarCloud Web API needs a token in
SONAR_TOKEN. It lives in the gitignored .env.local at the repo root (not the shell env). Load it and verify:
set -a; [ -f .env.local ] && . ./.env.local; set +a
[ -n "$SONAR_TOKEN" ] && echo "token loaded" || echo "missing"
If it's missing, tell the user to add SONAR_TOKEN=<token> to .env.local (create one at https://sonarcloud.io/account/security); it's a secret, so keep it only in .env.local, which is gitignored. Stop until it's set.
- Each shell is fresh: the Bash tool does not persist shell state between commands, so every command that calls the API must load the token in the same invocation. Prefix each API command with the loader, e.g.:
set -a; . ./.env.local; set +a
curl -s -u "$SONAR_TOKEN:" "https://sonarcloud.io/api/..."
(chained in one Bash call). The examples below omit the prefix for readability — always include it.
- Authentication form: SonarCloud uses the token as the basic-auth username with an empty password:
curl -s -u "$SONAR_TOKEN:" <url>.
- Never print the token — don't echo
SONAR_TOKEN or cat .env.local; only use it via -u "$SONAR_TOKEN:".
jq and gh are expected to be available (the repo already uses gh).
Project coordinates
This repo is imported into SonarCloud from GitHub, so the defaults are derived from the origin remote github.com/<owner>/<repo>:
- organization:
<owner> → lucasvieirasilva
- projectKey:
<owner>_<repo> → lucasvieirasilva_nx-plugins
Confirm the key resolves before fetching (a wrong key returns an empty/error payload):
curl -s -u "$SONAR_TOKEN:" \
"https://sonarcloud.io/api/components/show?component=lucasvieirasilva_nx-plugins" | jq '.component.key // .errors'
If it errors, ask the user for the correct projectKey/organization rather than guessing further.
When invoked
Phase 1: Determine scope (PR vs branch)
SonarCloud analyzes pull requests and branches separately, and PR analysis is scoped to new/changed code — which is almost always what you want. Resolve the target in this order:
- PR for the current branch (preferred):
gh pr view "$(git branch --show-current)" --json number -q .number
Use it as the pullRequest=<number> query parameter.
- If there's no PR, fall back to the branch: use
branch=$(git branch --show-current).
- If the user named a specific PR number or branch, use that instead.
Define a shell variable for the scope param, e.g. SCOPE="pullRequest=353" or SCOPE="branch=issue-348", and reuse it below.
Phase 2: Fetch findings
Fetch the three signal sources and trim each payload with jq so only relevant fields reach you.
-
Quality gate status (the headline pass/fail and which conditions failed):
curl -s -u "$SONAR_TOKEN:" \
"https://sonarcloud.io/api/qualitygates/project_status?projectKey=lucasvieirasilva_nx-plugins&$SCOPE" \
| jq '{status: .projectStatus.status, conditions: [.projectStatus.conditions[] | select(.status != "OK") | {metric: .metricKey, comparator: .comparator, threshold: .errorThreshold, actual: .actualValue}]}'
-
Issues (bugs, vulnerabilities, code smells) — unresolved only:
curl -s -u "$SONAR_TOKEN:" \
"https://sonarcloud.io/api/issues/search?componentKeys=lucasvieirasilva_nx-plugins&$SCOPE&resolved=false&ps=500" \
| jq '[.issues[] | {key, rule, type, severity, file: (.component | sub("^[^:]+:"; "")), line, message, effort, tags}]'
The component field is <projectKey>:<path>; the sub strips the <projectKey>: prefix to leave the repo-relative file path.
-
Security hotspots (reported separately from issues) — needing review:
curl -s -u "$SONAR_TOKEN:" \
"https://sonarcloud.io/api/hotspots/search?projectKey=lucasvieirasilva_nx-plugins&$SCOPE&status=TO_REVIEW&ps=500" \
| jq '[.hotspots[] | {key, file: (.component | sub("^[^:]+:"; "")), line, message, vulnerabilityProbability, securityCategory}]'
If issues and hotspots are both empty and the quality gate is OK/NONE, report that the project is clean for this scope and stop.
For context while triaging, also look at the actual change:
git diff origin/main..HEAD
Phase 3: Analyse and triage
For each finding, decide:
- Is it legitimate? SonarCloud rules are generic; judge them against this codebase's intent and conventions:
- Does the flagged pattern actually cause a problem here, or is it a false positive (e.g. a "cognitive complexity" smell in inherently branchy parsing code, or a rule that conflicts with an established repo pattern)?
- Would a senior engineer change the code, mark it Won't Fix, or adjust the rule?
- Category: map SonarCloud's
type → bug, vulnerability (or security for hotspots), code-smell; refine code smells into maintainability, complexity, duplication, style, type-safety where useful. Use false-positive when the finding doesn't hold.
- Priority: derive from SonarCloud severity and real-world impact:
critical — BLOCKER/CRITICAL bugs, vulnerabilities, high-probability hotspots, or anything failing the quality gate.
high — MAJOR bugs/error-handling/type-safety issues.
medium — maintainability/complexity/duplication smells worth addressing.
low — MINOR/INFO style or naming nits.
Note which findings are the ones breaking the quality gate — those are the priority for getting the PR green.
Phase 4: Summarize
Present a markdown table, sorted by priority (critical first):
| # | Priority | Type | File | Line(s) | Rule | Summary | Legitimate? | Action |
|---|----------|------|------|---------|------|---------|-------------|--------|
| 1 | critical | bug | packages/nx-python/src/foo.ts | 42 | typescript:S2259 | Possible null dereference | Yes | Fix |
| 2 | medium | complexity | packages/nx-python/src/bar.ts | 100 | typescript:S3776 | Cognitive complexity 21 > 15 | Debatable | Refactor |
Then give a short executive summary: quality gate status (and which conditions failed), total findings, how many legitimate, how many to fix vs skip, and whether fixing the legitimate ones would turn the gate green.
Auto-fix mode
If the user says "fix", "auto-fix", "apply", or similar, address the findings marked legitimate:
- Re-read the flagged code (≥20 lines of context) and confirm SonarCloud's finding holds in context.
- Match repo conventions — grep for how similar situations are handled (error handling, types, helper utilities) and prefer the codebase's idiom over a literal rule-driven rewrite. Follow docs/CODE_STYLE.md.
- Apply the smallest correct change. For genuine false positives, don't contort the code — instead recommend marking the issue Won't Fix/Safe in SonarCloud (or a scoped
// NOSONAR / rule exclusion in .sonarcloud.properties) and explain why; let the user make that call.
- Verify with the affected project's targets before claiming success:
pnpm nx affected -t lint test build
(or the specific pnpm nx <target> <project>). Report results honestly, including anything still failing.
Marking findings reviewed / safe (only when the user asks)
These are write operations against SonarCloud — only run them when the user explicitly says to (e.g. "mark the hotspots safe", "mark that as won't fix"). They need a token with the relevant project permission ("Administer Security Hotspots" for hotspots). Always include a comment justifying the decision. A 204 response means success; re-fetch afterward to confirm. Remember the token loader prefix (set -a; . ./.env.local; set +a).
Security hotspots — review a hotspot as SAFE (the regex/DoS case here is the common one) or FIXED/ACKNOWLEDGED:
curl -s -o /dev/null -w "status=%{http_code}\n" -u "$SONAR_TOKEN:" -X POST \
"https://sonarcloud.io/api/hotspots/change_status" \
--data-urlencode "hotspot=<HOTSPOT_KEY>" \
--data-urlencode "status=REVIEWED" \
--data-urlencode "resolution=SAFE" \
--data-urlencode "comment=<why this is not exploitable in context>"
This is what flips the new_security_hotspots_reviewed quality-gate condition green once every new hotspot is reviewed. Hotspot keys come from the hotspots/search call in Phase 2.
Issues (bug / vulnerability / code smell) — transition to wontfix or falsepositive, optionally with a comment:
curl -s -u "$SONAR_TOKEN:" -X POST "https://sonarcloud.io/api/issues/add_comment" \
--data-urlencode "issue=<ISSUE_KEY>" --data-urlencode "text=<justification>"
curl -s -u "$SONAR_TOKEN:" -X POST "https://sonarcloud.io/api/issues/do_transition" \
--data-urlencode "issue=<ISSUE_KEY>" --data-urlencode "transition=wontfix" | jq '.issue.resolution'
Prefer fixing the code over suppressing a real finding; reserve these for genuine false positives or accepted risk, and state the justification in the comment so it's auditable.
Rules
- Scope to new code / the PR by default — don't drown the user in pre-existing debt from the whole project unless they ask for a full-project review.
- Never hardcode or print
SONAR_TOKEN. Use it only via -u "$SONAR_TOKEN:".
- Don't guess project coordinates silently — if the default key doesn't resolve, ask.
- Be honest about false positives. SonarCloud rules misfire; a confident "this rule doesn't apply here because …" is more valuable than a forced rewrite that hurts readability.
- Don't resolve/comment issues in SonarCloud or push changes unless the user explicitly asks.