| 1 | --- |
| 2 | name: sonarqube-audit |
| 3 | description: Triage SonarCloud findings (issues, hotspots, code smells, vulnerabilities) for this project — search what's open, mark False Positive / Won't Fix / Confirm / Safe / Acknowledged / Fixed, batch-mark whole rule families. Use when the user asks to "review Sonar findings", "triage SonarCloud", "mark False Positive on Sonar", or anything mentioning sonarqube/sonarcloud, S2259, S5008, code smells, security hotspots, or sonarcloud.io. |
| 4 | --- |
| 5 | |
| 6 | # SonarCloud triage skill |
| 7 | |
| 8 | This skill drives the SonarCloud Web API |
| 9 | (<https://docs.sonarsource.com/sonarcloud/api/>) to enumerate findings and apply |
| 10 | triage decisions: False Positive / Won't Fix / Confirmed for issues; Reviewed |
| 11 | with one of Safe / Acknowledged / Fixed for hotspots. Family-mode lets |
| 12 | you mark every open finding for a rule in one go. |
| 13 | |
| 14 | The skill operates on the project configured in `.env` (see Setup). Scripts |
| 15 | auto-detect the repo root and write all artifacts under `<repo-root>/.local/`. |
| 16 | |
| 17 | ## MANDATORY — keep this skill alive |
| 18 | |
| 19 | **If you (the agent) discover a new pattern, gotcha, working flow, correction, |
| 20 | or any piece of knowledge while running this skill — update this `SKILL.md` |
| 21 | AND commit it BEFORE proceeding. Knowledge that isn't committed is lost.** |
| 22 | |
| 23 | Examples of things to capture: |
| 24 | - New rule with a known FP pattern (and the exact comment to use) |
| 25 | - A bulk-FP family that's safe to apply project-wide |
| 26 | - A SonarCloud API quirk (rate limits, undocumented response shapes) |
| 27 | - A new path/issue exclusion that's safer than per-finding marking |
| 28 | |
| 29 | ## Setup |
| 30 | |
| 31 | ### .env entries |
| 32 | |
| 33 | ```bash |
| 34 | # SonarCloud |
| 35 | SONAR_TOKEN='<paste your token from https://sonarcloud.io/account/security>' |
| 36 | SONAR_HOST_URL=https://sonarcloud.io |
| 37 | SONAR_PROJECT=<project_key, e.g. netdata_netdata> |
| 38 | SONAR_ORG=<organization_key, e.g. netdata> |
| 39 | ``` |
| 40 | |
| 41 | The token is used as **HTTP Basic auth username with empty password**: |
| 42 | `-u "$SONAR_TOKEN:"` (note the trailing colon). |
| 43 | |
| 44 | No browser tab is required — token-based auth is stable across sessions. |
| 45 | |
| 46 | ## Triage decision matrix |
| 47 | |
| 48 | ### Issues (Bug, Vulnerability, Code Smell) |
| 49 | |
| 50 | | Decision | API transition | When to use | |
| 51 | |--------------|-----------------|--------------------------------------------------------------------| |
| 52 | | Confirm | `confirm` | Sonar is right, we're going to fix it | |
| 53 | | Won't Fix | `wontfix` | Real but acceptable — won't fix (e.g., legacy code being deleted) | |
| 54 | | False Positive | `falsepositive` | Sonar is wrong (guard exists, unreachable, tool model error) | |
| 55 | |
| 56 | ### Security Hotspots |
| 57 | |
| 58 | Hotspots have a separate state machine. They go from `TO_REVIEW` to |
| 59 | `REVIEWED` with one of three resolutions: |
| 60 | |
| 61 | | Resolution | When to use | |
| 62 | |---------------|---------------------------------------------------------------| |
| 63 | | `SAFE` | Hotspot reviewed, code is fine as-is (no risk in context) | |
| 64 | | `ACKNOWLEDGED`| Risk understood, no immediate action — leave for future review | |
| 65 | | `FIXED` | Hotspot reviewed and the code was changed to remove the risk | |
| 66 | |
| 67 | ## ASCII-only comments — non-negotiable |
| 68 | |
| 69 | `api.sonarcloud.io` sits behind Cloudflare, which rejects bodies containing |
| 70 | non-ASCII bytes (em-dashes, smart quotes) with a 403 challenge. The scripts |
| 71 | fail before the network round-trip if non-ASCII is detected. |
| 72 | |
| 73 | - Use `--` instead of em-dash (U+2014). |
| 74 | - Use straight quotes `"` `'` instead of smart quotes. |
| 75 | |
| 76 | ## Workflow |
| 77 | |
| 78 | ### Step 1 — see what's open |
| 79 | |
| 80 | ``` |
| 81 | bash .agents/skills/sonarqube-audit/scripts/sonar-search.sh summary |
| 82 | ``` |
| 83 | |
| 84 | Prints per-rule counts of open issues + open hotspots. Use this to spot |
| 85 | high-volume rules that are candidates for family-mode bulk marking, and |
| 86 | project-wide quality-profile or exclusion changes. |
| 87 | |
| 88 | ### Step 2 — search for specific rule's findings |
| 89 | |
| 90 | Issues: |
| 91 | ``` |
| 92 | bash .agents/skills/sonarqube-audit/scripts/sonar-search.sh issues --rule cpp:S5827 |
| 93 | ``` |
| 94 | |
| 95 | Hotspots: |
| 96 | ``` |
| 97 | bash .agents/skills/sonarqube-audit/scripts/sonar-search.sh hotspots --status=TO_REVIEW \ |
| 98 | | jq '.hotspots[] | select(.ruleKey=="c:S5443")' |
| 99 | ``` |
| 100 | |
| 101 | ### Step 3 — triage |
| 102 | |
| 103 | #### Single finding |
| 104 | |
| 105 | ``` |
| 106 | bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh fp <ISSUE_KEY> "<COMMENT>" |
| 107 | bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh wontfix <ISSUE_KEY> "<COMMENT>" |
| 108 | bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh confirm <ISSUE_KEY> "<COMMENT>" |
| 109 | |
| 110 | bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh safe <HOTSPOT_KEY> "<COMMENT>" |
| 111 | bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh ack <HOTSPOT_KEY> "<COMMENT>" |
| 112 | bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh fixed <HOTSPOT_KEY> "<COMMENT>" |
| 113 | ``` |
| 114 | |
| 115 | #### Family mode (every open finding for a rule) |
| 116 | |
| 117 | ``` |
| 118 | bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh family-fp <RULE_ID> "<COMMENT>" |
| 119 | bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh family-safe <RULE_ID> "<COMMENT>" |
| 120 | ``` |
| 121 | |
| 122 | Family mode prints all matched keys and prompts before acting unless |
| 123 | `SONAR_MARK_YES=1` is set. |
| 124 | |
| 125 | ### Step 4 — dry runs |
| 126 | |
| 127 | ``` |
| 128 | SONAR_DRY_RUN=1 bash .agents/skills/sonarqube-audit/scripts/sonar-mark.sh fp KEY "Comment" |
| 129 | ``` |
| 130 | |
| 131 | In dry-run mode, **write** API calls (mark issues, change hotspot status, |
| 132 | add comments) are printed but not executed. **Read** API calls (issue |
| 133 | search, hotspot search used to enumerate findings in family mode) still |
| 134 | run -- otherwise family mode could not show what it would have acted on. |
| 135 | |
| 136 | ## What this skill does NOT do |
| 137 | |
| 138 | - **Disable rules**: use `api/qualityprofiles/deactivate_rule` directly, or do |
| 139 | it in the SonarCloud UI under Quality Profiles. |
| 140 | - **Configure issue exclusions**: use Project Settings -> Analysis Scope -> |
| 141 | Issue Exclusions in the UI. |
| 142 | - **Rule-tuning audit**: when you want a per-rule KEEP/DISABLE/NARROW decision |
| 143 | log, document that separately (it's project-wide policy, not per-finding |
| 144 | triage). |
| 145 | |
| 146 | ## Project-wide quality profile / exclusion configuration |
| 147 | |
| 148 | Effective profile lookup: |
| 149 | ``` |
| 150 | GET /api/qualityprofiles/search?project=$SONAR_PROJECT&organization=$SONAR_ORG |
| 151 | ``` |
| 152 | |
| 153 | To make project-wide changes (deactivate a rule or override severity): |
| 154 | 1. Copy the inherited profile (`api/qualityprofiles/copy`) |
| 155 | 2. Make your edits there |
| 156 | 3. Assign the project to the new profile (`api/qualityprofiles/add_project`) |
| 157 | |
| 158 | This is a one-shot operation per language. SonarCloud language keys are: |
| 159 | `c`, `cpp`, `go`, `javascript`, `py`, `shell`, `plsql`, `docker`, `css`, |
| 160 | `ipynb`, `php` (and others depending on the project). Note the rule-id |
| 161 | namespaces in `api/issues/search` results may differ from the language |
| 162 | keys -- e.g. shell rules use the `shelldre:` prefix, Go rules can use |
| 163 | either `go:` or `godre:` depending on which analyzer fired -- so the |
| 164 | language argument to qualityprofile APIs is the SHORT key (`shell`, |
| 165 | `go`), not the rule-namespace prefix. |
| 166 | |
| 167 | Keep a record of profile decisions in a project-local doc under |
| 168 | `.local/audits/sonarqube/`. |
| 169 | |
| 170 | ## Failure modes — quick diagnosis |
| 171 | |
| 172 | | Symptom | Likely cause | |
| 173 | |----------------------------------------|-------------------------------------------------------------| |
| 174 | | HTTP 401 / 403 with HTML body | Token wrong/expired, or Cloudflare blocking non-ASCII | |
| 175 | | Token works for issues but not hotspots| Hotspot endpoints have separate auth checks — token must have `Browse` permission | |
| 176 | | Family-mode appears to stop at 500 | Outdated -- `sonar-mark.sh` family-mode now paginates transparently via `sq_paginate`. If you still see truncation, check `sq_paginate`'s array-key recognition list. | |
| 177 | | `falsepositive` transition rejected | Issue is not in `OPEN` or `CONFIRMED` state — check current status | |
| 178 | | Hotspot transition rejected | Hotspot already in `REVIEWED` state — re-check before retry | |
| 179 | |
| 180 | ## Recurring tips |
| 181 | |
| 182 | - `api/issues/search` is paged at `ps=500` max. The `sq_paginate` helper |
| 183 | in `_lib.sh` walks every page until `paging.total`; use it from any |
| 184 | new script instead of re-implementing the loop. |
| 185 | - Hotspot `ruleKey` filtering is client-side (search only filters by |
| 186 | status/project), so the family-mode helper does it in Python. |
| 187 | - An issue may be transitioned only between certain states; if you get |
| 188 | "Cannot do transition from STATUS X to Y", it's already past that state. |
| 189 | - `SONAR_DRY_RUN=1` is the right knob when iterating on comments |
| 190 | before committing to a bulk operation. |