tts-voice-creator-clone-and.../architecture/sonar-triage.md
mARTin-B78 9d93b4fb89 fix(qa): run Python tests with an interpreter that has the project dependencies
Agents see /usr/bin/python3 first, which has no fastapi.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 11:51:33 +02:00

65 lines
6.5 KiB
Markdown

# SonarQube triage loop
Local script `scripts/sonar_triage.mjs` (`npm run sonar:triage`). Dry-run by default; nothing is pushed, ever.
```
SonarQube /api/issues/search (GET, paged, OPEN/CONFIRMED/REOPENED)
|
classify --skip-list--> SKIPPED (reported only)
|
+----+-----------------------------+
SMALL MEDIUM / LARGE
| (--apply --fix-small) | (--apply)
task file -> `claude -p` group by rule (<=40 locations) -> `gh issue create`
-> ONE local commit (labels sonar, agent-fix; dedupe marker)
`fix(sonar): ...` |
`multica issue create --assignee sonar-fixer`
-> agent fixes, local commit only
```
## Classification
- SMALL: severity INFO/MINOR (or MAJOR with effort <= 5 min) AND rule in `scripts/sonar_triage.rules.json` AND file under `core/ routes/ static/js/ scripts/`.
- Never small: any VULNERABILITY; path or message mentioning auth/crypto/async/thread/lock/SQL/secret/token/password; files elsewhere (incl. tests).
- LARGE: severity BLOCKER/CRITICAL or effort > 60 min; otherwise MEDIUM.
- SKIPPED: matches an entry of `scripts/sonar_triage.skip.json` (rule, file regex, message regex; every given field must match). Entries: server.py 0.0.0.0 bind, tmp-dir dev script, Math.random ids, http:// LAN URLs, md5 cache key.
- Allowlist (each reason is in the JSON): python/javascript S1481 unused local, S1116 empty statement, javascript S1128 unused import, python/javascript S125 commented-out code.
## Flags
`--dry-run` (default) | `--apply` | `--since-new-code` (default) | `--all` | `--json <file>` | `--max-issues N` | `--cap N` (GitHub issues per run, default 10) | `--fix-small` (needs `--apply`) | `--list-rules`.
## GitHub issues
One per rule (all files); title `[sonar] <rule>: <short> in N file(s)`; body has a table of file, line, Sonar key, message (capped at 40 rows, then 'and N more'), rule link, effort, approach, acceptance. A rule with more than 40 locations is split into numbered parts (`part 1/3`), 40 locations each. Hidden marker `<!-- sonar-keys: k1,k2 -->` lists every key of the part; an open `sonar` issue containing any of the keys suppresses a new one. Bodies contain paths/lines only, no code. If `gh auth status` fails the script reports and continues.
## multica hookup
Preferred: a multica **webhook autopilot** (Autopilots -> New autopilot -> Trigger: Webhook, assignee `sonar-fixer`, output mode Create issue, project Voice Creator Clone & Design 2). Multica shows the webhook URL after the autopilot is created; it carries its own secret, so save it only in `~/.config/multica-webhook` (chmod 600) or `MULTICA_WEBHOOK_URL`, never in the repo. After each GitHub issue the script POSTs JSON (`source, rule, title, github_issue_url, files, sonar_keys, effort_min, body`) to it, passing the URL to curl on stdin only. Fallback if no webhook is configured: the CLI command below.
After a GitHub issue is created the script runs `multica issue create --project <id> --assignee sonar-fixer --description-stdin` (the multica issue links the GitHub URL; assigning starts the agent run). Override with `MULTICA_AGENT`, `MULTICA_PROJECT`. Failure is reported, not fatal. Agent `sonar-fixer` instructions: see the end of this file.
## --drain (one issue at a time, with delivery check)
`npm run sonar:triage -- --apply --drain [--lane refactor] [--timeout 60] [--resends 1]` takes the open GitHub issues labelled `sonar` + `agent-fix` (or `agent-refactor`), oldest first, and for each one: fires the webhook, then polls GitHub every minute until the agent answers (a new comment, the label `fixed-local`, or the issue closed). If nothing arrives within `--timeout` minutes it resends once (`--resends`), and if it still stays silent it STOPS and reports the stalled issue, so nothing else queues behind it. Reason: multica has accepted webhook calls (HTTP 200) without creating an issue, so a 200 is not proof of delivery. One issue at a time also respects the agents' concurrency of 1.
## --fix-small
Refuses on a dirty tracked tree. Writes a task file to a temp dir (not committed), runs `claude -p` with only Read/Edit/Grep/Glob and Bash for check-frontend, `node --test`, git add/commit/status/diff, then verifies the new commit count and clean tree. Local commit only.
## Secrets
The token is read inside the script from `~/.config/sonar-token` (or `SONAR_TOKEN`) and sent as HTTP Basic auth (token as user, empty password). It is never printed, put in argv/URLs or written to files; a unit test asserts it is absent from output.
## Run
```
npm run sonar:triage # dry-run, new code
npm run sonar:triage -- --all --json /tmp/t.json
npm run sonar:triage -- --apply --cap 5 # create GitHub + multica issues
npm run sonar:triage -- --apply --fix-small
```
## Rollback
Local fix commits: `git reset --hard <sha before>` / `git revert`. Issues: close the GitHub issue and the multica issue. Nothing is pushed by the script.
## sonar-fixer agent instructions
Fix only the given Sonar issue. Read CLAUDE.md and PROJECT_MAP.md first. Run `node scripts/check-frontend.mjs` and Python `unittest` with an isolated HOME; tests mock the API and import from tests/_guard.js. Browser (Playwright) specs run against the live app and cannot see worktree edits: say which checks you did not run. Python: `/usr/bin/python3` has no fastapi; use `/home/sparky/miniforge3/bin/python3` (or `npm run qa -- --only pyunit`, which picks the right interpreter) and never report a failure that comes from a missing module as a test failure. One local Conventional Commit `fix(sonar): ...`; never push; never touch secrets; if a design decision is needed, stop and comment.
When done:
1. Comment on the multica issue: commit SHA, files changed, what you verified, checks NOT run, findings skipped as false positives (with reason).
2. Post the same report on the GitHub issue from `github_issue_url`: `gh issue comment <number> --body-file -` (paths and line numbers only, no code; say the commit is LOCAL and not pushed), add the label `fixed-local`, then close it: `gh issue close <number> --reason completed`. If you fixed only part of the findings, do NOT close it: list what is left in the comment.
3. When the fix is complete and reported (steps 1 and 2), move the multica issue to Done. If only part is fixed, or a design decision is needed, or you could not fix it: comment on both issues, leave the GitHub issue open, and leave the multica issue in In Review (or Blocked if you need an answer).