@northbridge-security/secureai 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/README.md +122 -0
- package/.claude/commands/architect/clean.md +978 -0
- package/.claude/commands/architect/kiss.md +762 -0
- package/.claude/commands/architect/review.md +704 -0
- package/.claude/commands/catchup.md +90 -0
- package/.claude/commands/code.md +115 -0
- package/.claude/commands/commit.md +1218 -0
- package/.claude/commands/cover.md +1298 -0
- package/.claude/commands/fmea.md +275 -0
- package/.claude/commands/kaizen.md +312 -0
- package/.claude/commands/pr.md +503 -0
- package/.claude/commands/todo.md +99 -0
- package/.claude/commands/worktree.md +738 -0
- package/.claude/commands/wrapup.md +103 -0
- package/LICENSE +183 -0
- package/README.md +108 -0
- package/dist/cli.js +75634 -0
- package/docs/agents/devops-reviewer.md +889 -0
- package/docs/agents/kiss-simplifier.md +1088 -0
- package/docs/agents/typescript.md +8 -0
- package/docs/guides/README.md +109 -0
- package/docs/guides/agents.clean.arch.md +244 -0
- package/docs/guides/agents.clean.arch.ts.md +1314 -0
- package/docs/guides/agents.gotask.md +1037 -0
- package/docs/guides/agents.markdown.md +1209 -0
- package/docs/guides/agents.onepassword.md +285 -0
- package/docs/guides/agents.sonar.md +857 -0
- package/docs/guides/agents.tdd.md +838 -0
- package/docs/guides/agents.tdd.ts.md +1062 -0
- package/docs/guides/agents.typesript.md +1389 -0
- package/docs/guides/github-mcp.md +1075 -0
- package/package.json +130 -0
- package/packages/secureai-cli/src/cli.ts +21 -0
- package/tasks/README.md +880 -0
- package/tasks/aws.yml +64 -0
- package/tasks/bash.yml +118 -0
- package/tasks/bun.yml +738 -0
- package/tasks/claude.yml +183 -0
- package/tasks/docker.yml +420 -0
- package/tasks/docs.yml +127 -0
- package/tasks/git.yml +1336 -0
- package/tasks/gotask.yml +132 -0
- package/tasks/json.yml +77 -0
- package/tasks/markdown.yml +95 -0
- package/tasks/onepassword.yml +350 -0
- package/tasks/security.yml +102 -0
- package/tasks/sonar.yml +437 -0
- package/tasks/template.yml +74 -0
- package/tasks/vscode.yml +103 -0
- package/tasks/yaml.yml +121 -0
|
@@ -0,0 +1,857 @@
|
|
|
1
|
+
# SonarQube Integration Guide for AI Agents
|
|
2
|
+
|
|
3
|
+
This guide explains how AI agents can integrate with SonarQube/SonarCloud for automated code quality analysis, security scanning, and PR review workflows. Target audience: AI code assistants working with repositories that use SonarQube for quality gates.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
SonarQube provides automated code quality and security analysis integrated into CI/CD workflows. AI agents can download analysis results programmatically, review findings, and fix issues automatically without requiring manual SonarCloud UI access.
|
|
8
|
+
|
|
9
|
+
**Key capabilities:**
|
|
10
|
+
|
|
11
|
+
- Download complete analysis results via GoTask commands
|
|
12
|
+
- Parse issues and security hotspots from downloaded reports
|
|
13
|
+
- Address findings programmatically (fix real issues, suppress false positives)
|
|
14
|
+
- Integrate with `/pr:fix` workflow for automated PR remediation
|
|
15
|
+
- Track quality gate status and blocking issues
|
|
16
|
+
|
|
17
|
+
**Supported workflows:**
|
|
18
|
+
|
|
19
|
+
- **PR-based analysis**: Get issues specific to a pull request
|
|
20
|
+
- **Branch analysis**: Get issues for default branch
|
|
21
|
+
- **Local scanning**: Run sonar-scanner locally before pushing
|
|
22
|
+
- **Automated fixes**: Bulk remediation of security hotspots and code smells
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
### Repository Requirements
|
|
27
|
+
|
|
28
|
+
**Minimum setup** (may not exist in all repositories):
|
|
29
|
+
|
|
30
|
+
- `sonar-project.properties` file in repository root
|
|
31
|
+
- `SONAR_TOKEN` environment variable or secret
|
|
32
|
+
- GitHub Actions workflow with SonarQube step (optional)
|
|
33
|
+
|
|
34
|
+
**Typical structure:**
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
repository/
|
|
38
|
+
├── sonar-project.properties # SonarQube configuration
|
|
39
|
+
├── .github/
|
|
40
|
+
│ ├── workflows/
|
|
41
|
+
│ │ └── ci.yml # CI workflow with SonarQube job
|
|
42
|
+
│ └── actions/
|
|
43
|
+
│ └── sonar/
|
|
44
|
+
│ └── action.yml # Reusable SonarQube action
|
|
45
|
+
├── .env # Local secrets (gitignored)
|
|
46
|
+
└── tasks/
|
|
47
|
+
└── sonar.yml # GoTask automation (if using GoTask)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**If repository lacks SonarQube setup:**
|
|
51
|
+
|
|
52
|
+
The repository may not have SonarQube configured. Check for these files before attempting analysis:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Check for sonar-project.properties
|
|
56
|
+
[ -f sonar-project.properties ] && echo "SonarQube configured" || echo "No SonarQube"
|
|
57
|
+
|
|
58
|
+
# Check for SonarQube GitHub Action
|
|
59
|
+
grep -r "sonar" .github/workflows/ 2>/dev/null
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If not configured, skip SonarQube analysis or suggest setup (see [Setting Up SonarQube](#setting-up-sonarqube)).
|
|
63
|
+
|
|
64
|
+
### Token Setup
|
|
65
|
+
|
|
66
|
+
**For local analysis:**
|
|
67
|
+
|
|
68
|
+
Add to `.env` file (gitignored):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# SonarQube/SonarCloud authentication token
|
|
72
|
+
SONAR_TOKEN=your-token-here
|
|
73
|
+
|
|
74
|
+
# Or use 1Password reference
|
|
75
|
+
SONAR_TOKEN=op://Private/SonarCloud/API Token/token
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**For CI/CD:**
|
|
79
|
+
|
|
80
|
+
Token should be configured as GitHub secret:
|
|
81
|
+
|
|
82
|
+
- **Secret name**: `SONAR_TOKEN`
|
|
83
|
+
- **Where**: Repository Settings → Secrets and variables → Actions
|
|
84
|
+
|
|
85
|
+
## GoTask Integration
|
|
86
|
+
|
|
87
|
+
### Available Commands
|
|
88
|
+
|
|
89
|
+
**Analysis commands:**
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Download complete analysis results (recommended)
|
|
93
|
+
task sonar:download
|
|
94
|
+
|
|
95
|
+
# View most recent downloaded report
|
|
96
|
+
task sonar:issues
|
|
97
|
+
|
|
98
|
+
# Run local scan (requires sonar-scanner installed)
|
|
99
|
+
task sonar:scan
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Setup commands:**
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Install sonar-scanner CLI (macOS/Linux)
|
|
106
|
+
task sonar:setup
|
|
107
|
+
|
|
108
|
+
# Show all available commands
|
|
109
|
+
task sonar:help
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Download Analysis Results
|
|
113
|
+
|
|
114
|
+
The `sonar:download` command fetches complete analysis results from SonarQube API and generates a human-readable report.
|
|
115
|
+
|
|
116
|
+
**What it does:**
|
|
117
|
+
|
|
118
|
+
1. Detects PR context (or default branch if no PR)
|
|
119
|
+
2. Fetches issues, security hotspots, and quality gate status
|
|
120
|
+
3. Generates timestamped report in `.logs/sonar/`
|
|
121
|
+
4. Opens report in VSCode (if available)
|
|
122
|
+
|
|
123
|
+
**Example output:**
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
$ task sonar:download
|
|
127
|
+
|
|
128
|
+
ℹ Analyzing PR #4: feat(installer): Phase 2 - Agent installation
|
|
129
|
+
ℹ Project: northbridge-security_ai-toolkit
|
|
130
|
+
ℹ Branch: feat/installer-ph2 → main
|
|
131
|
+
|
|
132
|
+
❌ Quality Gate: ERROR
|
|
133
|
+
ℹ Downloaded 237 issues + 49 hotspots → .logs/sonar/issues-20251118-115543.txt
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Report structure:**
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
SonarQube Analysis Report
|
|
140
|
+
=========================
|
|
141
|
+
Project: northbridge-security_ai-toolkit
|
|
142
|
+
Analysis: PR #4
|
|
143
|
+
Date: 2025-11-18 11:55:43
|
|
144
|
+
|
|
145
|
+
Quality Gate: ERROR
|
|
146
|
+
Failed Conditions:
|
|
147
|
+
- coverage: 65.2% (threshold: 80%)
|
|
148
|
+
- duplicated_lines_density: 9.1% (threshold: 3%)
|
|
149
|
+
|
|
150
|
+
Issues: 237
|
|
151
|
+
By Severity:
|
|
152
|
+
Blocker: 4
|
|
153
|
+
Critical: 73
|
|
154
|
+
Major: 76
|
|
155
|
+
Minor: 78
|
|
156
|
+
|
|
157
|
+
Security Hotspots: 49
|
|
158
|
+
To Review: 49
|
|
159
|
+
Reviewed: 0
|
|
160
|
+
|
|
161
|
+
═══════════════════════════════════════════════════════════════
|
|
162
|
+
DETAILED ISSUES
|
|
163
|
+
═══════════════════════════════════════════════════════════════
|
|
164
|
+
|
|
165
|
+
[BLOCKER] .github/workflows/approve.yml:24
|
|
166
|
+
Type: CODE_SMELL
|
|
167
|
+
Rule: javascript:S2076
|
|
168
|
+
Message: Make sure that executing this OS command is safe here.
|
|
169
|
+
───────────────────────────────────────────────────────────────
|
|
170
|
+
...
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Programmatic Analysis
|
|
174
|
+
|
|
175
|
+
**Read downloaded reports:**
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# Most recent report
|
|
179
|
+
REPORT=$(ls -t .logs/sonar/issues-*.txt 2>/dev/null | head -1)
|
|
180
|
+
|
|
181
|
+
# Count issues by severity
|
|
182
|
+
BLOCKER=$(grep "^\[BLOCKER\]" "$REPORT" | wc -l)
|
|
183
|
+
CRITICAL=$(grep "^\[CRITICAL\]" "$REPORT" | wc -l)
|
|
184
|
+
|
|
185
|
+
# Extract specific file issues
|
|
186
|
+
grep "src/tasks/bash/utils.ts" "$REPORT"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Parse raw JSON data:**
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Raw API responses are also saved
|
|
193
|
+
RAW_JSON=$(ls -t .logs/sonar/issues-*-raw.json 2>/dev/null | head -1)
|
|
194
|
+
|
|
195
|
+
# Extract high-severity issues
|
|
196
|
+
jq '.issues[] | select(.severity == "BLOCKER" or .severity == "CRITICAL")' "$RAW_JSON"
|
|
197
|
+
|
|
198
|
+
# Group by file
|
|
199
|
+
jq -r '.issues[] | "\(.component | split(":")[1]):\(.line)"' "$RAW_JSON" | sort | uniq -c
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Analyzing Findings
|
|
203
|
+
|
|
204
|
+
### Issue Categories
|
|
205
|
+
|
|
206
|
+
**By severity:**
|
|
207
|
+
|
|
208
|
+
- **BLOCKER**: Breaks core functionality, must fix immediately
|
|
209
|
+
- **CRITICAL**: High-impact bugs or security vulnerabilities
|
|
210
|
+
- **MAJOR**: Moderate-impact issues (complexity, maintainability)
|
|
211
|
+
- **MINOR**: Low-impact code smells (style, minor improvements)
|
|
212
|
+
|
|
213
|
+
**By type:**
|
|
214
|
+
|
|
215
|
+
- **BUG**: Logic errors, incorrect behavior
|
|
216
|
+
- **VULNERABILITY**: Security weaknesses
|
|
217
|
+
- **CODE_SMELL**: Maintainability issues
|
|
218
|
+
- **SECURITY_HOTSPOT**: Code requiring security review
|
|
219
|
+
|
|
220
|
+
### Security Hotspots
|
|
221
|
+
|
|
222
|
+
Security hotspots require manual review to determine if they're real vulnerabilities or false positives.
|
|
223
|
+
|
|
224
|
+
**Hotspot workflow:**
|
|
225
|
+
|
|
226
|
+
1. **Download report**: `task sonar:download`
|
|
227
|
+
2. **Review each hotspot**: Check the code context
|
|
228
|
+
3. **Determine action**:
|
|
229
|
+
- **Real issue**: Fix the vulnerability
|
|
230
|
+
- **False positive**: Add suppression comment with justification
|
|
231
|
+
4. **Document decision**: Add inline comments explaining why
|
|
232
|
+
|
|
233
|
+
**Hotspot severity levels:**
|
|
234
|
+
|
|
235
|
+
- **HIGH**: Likely security vulnerability, immediate attention
|
|
236
|
+
- **MEDIUM**: Potential security issue, review carefully
|
|
237
|
+
- **LOW**: Minor security concern, low risk
|
|
238
|
+
|
|
239
|
+
**Example hotspot review:**
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// Security hotspot: Command injection warning
|
|
243
|
+
// Line 37: execSync('shfmt -d "' + file + '"')
|
|
244
|
+
|
|
245
|
+
// Analysis:
|
|
246
|
+
// - file variable comes from discoverFiles() function
|
|
247
|
+
// - discoverFiles() returns file paths from filesystem
|
|
248
|
+
// - Filenames could contain special characters like quotes, semicolons
|
|
249
|
+
// - This creates a command injection vulnerability
|
|
250
|
+
|
|
251
|
+
// FIX: Use proper shell escaping
|
|
252
|
+
import { escapeShellArg } from "./utils";
|
|
253
|
+
execSync("shfmt -d " + escapeShellArg(file));
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Example false positive:**
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
// Security hotspot: Hard-coded password
|
|
260
|
+
// Line 76: const token = 'github_pat_1234567890abcd';
|
|
261
|
+
|
|
262
|
+
// Analysis:
|
|
263
|
+
// - This is a test file (tests/integration/github-mcp.test.ts)
|
|
264
|
+
// - Token is clearly a fake placeholder (sequential characters)
|
|
265
|
+
// - Not a real secret
|
|
266
|
+
|
|
267
|
+
// SUPPRESSION: Document false positive
|
|
268
|
+
// nosemgrep: generic.secrets.security.detected-generic-secret.detected-generic-secret
|
|
269
|
+
const token = "github_pat_1234567890abcd"; // Test fixture, not real secret
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Suppression Patterns
|
|
273
|
+
|
|
274
|
+
**When to suppress:**
|
|
275
|
+
|
|
276
|
+
- Test fixtures with fake credentials
|
|
277
|
+
- Hardcoded commands with no user input
|
|
278
|
+
- Simple regex patterns flagged as ReDoS
|
|
279
|
+
- Permission checks in test cleanup code
|
|
280
|
+
- Math.random() used for non-security purposes
|
|
281
|
+
|
|
282
|
+
**Suppression format:**
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// SECURITY: [Explanation of why this is safe]
|
|
286
|
+
// nosemgrep: [rule-id]
|
|
287
|
+
[code that triggered warning]
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Common suppression rules:**
|
|
291
|
+
|
|
292
|
+
| Issue Type | Semgrep Rule ID |
|
|
293
|
+
| ------------------ | ------------------------------------------------------------------------------------ |
|
|
294
|
+
| Generic secrets | `generic.secrets.security.detected-generic-secret.detected-generic-secret` |
|
|
295
|
+
| Command injection | `javascript.lang.security.audit.unsafe-exec.unsafe-exec` |
|
|
296
|
+
| ReDoS | `javascript.lang.security.audit.detect-non-literal-regexp.detect-non-literal-regexp` |
|
|
297
|
+
| Weak crypto | `javascript.lang.security.audit.detect-pseudorandom-usage.detect-pseudorandom-usage` |
|
|
298
|
+
| Unsafe permissions | `javascript.lang.security.audit.unsafe-permissions.unsafe-permissions` |
|
|
299
|
+
|
|
300
|
+
## The /pr:fix Workflow
|
|
301
|
+
|
|
302
|
+
The `/pr:fix` slash command integrates SonarQube analysis into automated PR remediation.
|
|
303
|
+
|
|
304
|
+
**Workflow overview:**
|
|
305
|
+
|
|
306
|
+
1. **Detect PR context** - Identifies current branch and PR number
|
|
307
|
+
2. **Download PR comments** - Fetches GitHub PR review comments
|
|
308
|
+
3. **Download workflow logs** - Gets CI/CD failure details
|
|
309
|
+
4. **Download SonarQube analysis** - Runs `task sonar:download`
|
|
310
|
+
5. **Analyze findings** - Categorizes issues by priority
|
|
311
|
+
6. **Fix blocking issues** - Addresses critical/blocker issues automatically
|
|
312
|
+
7. **Update PR review documentation** - Tracks progress in `.pr.review.local.md`
|
|
313
|
+
|
|
314
|
+
**Usage:**
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Run in repository with open PR
|
|
318
|
+
/pr:fix
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**What it does with SonarQube:**
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
// Phase 3: Download SonarQube analysis
|
|
325
|
+
await bash("task sonar:download");
|
|
326
|
+
|
|
327
|
+
// Read downloaded report
|
|
328
|
+
const report = readFile(".logs/sonar/issues-*.txt");
|
|
329
|
+
|
|
330
|
+
// Parse findings
|
|
331
|
+
const blockers = parseIssues(report, "BLOCKER");
|
|
332
|
+
const criticals = parseIssues(report, "CRITICAL");
|
|
333
|
+
const hotspots = parseSecurityHotspots(report);
|
|
334
|
+
|
|
335
|
+
// Prioritize fixes
|
|
336
|
+
const mustFix = [...blockers, ...hotspots.filter((h) => h.severity === "HIGH")];
|
|
337
|
+
|
|
338
|
+
// Fix each issue programmatically
|
|
339
|
+
for (const issue of mustFix) {
|
|
340
|
+
await fixIssue(issue);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Update documentation
|
|
344
|
+
await updatePRReview({ fixed: mustFix.length, remaining: criticals.length });
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Example `/pr:fix` output:**
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
Phase 3: Downloading SonarQube analysis...
|
|
351
|
+
✓ Downloaded 237 issues + 49 hotspots
|
|
352
|
+
|
|
353
|
+
Analyzing findings:
|
|
354
|
+
- 4 BLOCKER issues (immediate fix required)
|
|
355
|
+
- 73 CRITICAL issues (high priority)
|
|
356
|
+
- 49 security hotspots (11 HIGH, 8 MEDIUM, 30 LOW)
|
|
357
|
+
|
|
358
|
+
Fixing BLOCKER issues:
|
|
359
|
+
✓ Fixed: .github/workflows/approve.yml:24 (command injection)
|
|
360
|
+
✓ Fixed: .github/actions/sonar/action.yml:92 (command injection)
|
|
361
|
+
✓ Fixed: src/tasks/bash/utils.ts:24 (command injection)
|
|
362
|
+
✓ Fixed: src/tasks/json/utils.ts:208 (incomplete escaping)
|
|
363
|
+
|
|
364
|
+
Addressing HIGH priority security hotspots:
|
|
365
|
+
✓ Fixed: src/tasks/bash/format-check.ts:37 (added escapeShellArg)
|
|
366
|
+
✓ Fixed: src/tasks/bash/format.ts:44 (added escapeShellArg)
|
|
367
|
+
✓ Fixed: src/tasks/bash/lint.ts:34 (added escapeShellArg)
|
|
368
|
+
✓ Documented: tests/integration/github-mcp.test.ts:76 (test fixture)
|
|
369
|
+
|
|
370
|
+
Updated: .pr.review.local.md
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Result:**
|
|
374
|
+
|
|
375
|
+
- All blocking issues fixed
|
|
376
|
+
- Progress tracked in `.pr.review.local.md`
|
|
377
|
+
- PR ready for review with clean quality gate
|
|
378
|
+
|
|
379
|
+
## Setting Up SonarQube
|
|
380
|
+
|
|
381
|
+
If repository doesn't have SonarQube configured, here's how to set it up.
|
|
382
|
+
|
|
383
|
+
### SonarCloud Project Setup
|
|
384
|
+
|
|
385
|
+
**1. Create SonarCloud project:**
|
|
386
|
+
|
|
387
|
+
- Go to https://sonarcloud.io
|
|
388
|
+
- Log in with GitHub account
|
|
389
|
+
- Click "+ " → "Analyze new project"
|
|
390
|
+
- Select repository
|
|
391
|
+
- Choose "With GitHub Actions" setup method
|
|
392
|
+
|
|
393
|
+
**2. Configure GitHub secret:**
|
|
394
|
+
|
|
395
|
+
- Copy SonarCloud token from setup page
|
|
396
|
+
- Go to GitHub repo → Settings → Secrets and variables → Actions
|
|
397
|
+
- Create new secret:
|
|
398
|
+
- **Name**: `SONAR_TOKEN`
|
|
399
|
+
- **Value**: [paste token]
|
|
400
|
+
|
|
401
|
+
### Configuration File
|
|
402
|
+
|
|
403
|
+
Create `sonar-project.properties` in repository root:
|
|
404
|
+
|
|
405
|
+
```properties
|
|
406
|
+
# SonarCloud Configuration
|
|
407
|
+
sonar.projectKey=organization_repository-name
|
|
408
|
+
sonar.organization=organization-name
|
|
409
|
+
|
|
410
|
+
# Project metadata
|
|
411
|
+
sonar.projectName=Repository Name
|
|
412
|
+
sonar.projectVersion=1.0
|
|
413
|
+
|
|
414
|
+
# Source code
|
|
415
|
+
sonar.sources=src
|
|
416
|
+
sonar.tests=tests
|
|
417
|
+
sonar.sourceEncoding=UTF-8
|
|
418
|
+
|
|
419
|
+
# Language-specific settings
|
|
420
|
+
sonar.javascript.lcov.reportPaths=.logs/coverage/lcov.info
|
|
421
|
+
sonar.testExecutionReportPaths=.logs/test-results/junit.xml
|
|
422
|
+
|
|
423
|
+
# Exclusions
|
|
424
|
+
sonar.exclusions=\
|
|
425
|
+
**/node_modules/**,\
|
|
426
|
+
**/dist/**,\
|
|
427
|
+
**/coverage/**,\
|
|
428
|
+
**/.logs/**,\
|
|
429
|
+
**/tests/**/*.test.ts
|
|
430
|
+
|
|
431
|
+
sonar.test.inclusions=\
|
|
432
|
+
tests/**/*.test.ts,\
|
|
433
|
+
**/*.test.ts
|
|
434
|
+
|
|
435
|
+
# Coverage exclusions
|
|
436
|
+
sonar.coverage.exclusions=\
|
|
437
|
+
tests/**,\
|
|
438
|
+
**/*.test.ts,\
|
|
439
|
+
**/types/**
|
|
440
|
+
|
|
441
|
+
# Quality gate
|
|
442
|
+
sonar.qualitygate.wait=false
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Key settings:**
|
|
446
|
+
|
|
447
|
+
| Property | Purpose | Example |
|
|
448
|
+
| ----------------------------------- | ----------------------- | -------------------------- |
|
|
449
|
+
| `sonar.projectKey` | Unique identifier | `org_repo-name` |
|
|
450
|
+
| `sonar.organization` | SonarCloud organization | `your-org` |
|
|
451
|
+
| `sonar.sources` | Source code directory | `src` |
|
|
452
|
+
| `sonar.tests` | Test directory | `tests` |
|
|
453
|
+
| `sonar.javascript.lcov.reportPaths` | Coverage report path | `.logs/coverage/lcov.info` |
|
|
454
|
+
|
|
455
|
+
### GitHub Actions Integration
|
|
456
|
+
|
|
457
|
+
**Create reusable action** (`.github/actions/sonar/action.yml`):
|
|
458
|
+
|
|
459
|
+
```yaml
|
|
460
|
+
name: "SonarQube Analysis"
|
|
461
|
+
description: "Runs SonarQube/SonarCloud analysis with sonar-scanner CLI"
|
|
462
|
+
|
|
463
|
+
inputs:
|
|
464
|
+
github-token:
|
|
465
|
+
description: "GitHub token for authentication"
|
|
466
|
+
required: true
|
|
467
|
+
sonar-token:
|
|
468
|
+
description: "SonarQube/SonarCloud token for authentication"
|
|
469
|
+
required: true
|
|
470
|
+
sonar-host-url:
|
|
471
|
+
description: "SonarQube/SonarCloud host URL"
|
|
472
|
+
required: false
|
|
473
|
+
default: "https://sonarcloud.io"
|
|
474
|
+
|
|
475
|
+
runs:
|
|
476
|
+
using: "composite"
|
|
477
|
+
steps:
|
|
478
|
+
- name: Install sonar-scanner
|
|
479
|
+
shell: bash
|
|
480
|
+
run: |
|
|
481
|
+
curl -sSL https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.8.0.2856-linux.zip -o /tmp/sonar-scanner.zip
|
|
482
|
+
unzip -q /tmp/sonar-scanner.zip -d /tmp/
|
|
483
|
+
echo "/tmp/sonar-scanner-4.8.0.2856-linux/bin" >> $GITHUB_PATH
|
|
484
|
+
|
|
485
|
+
- name: Run SonarQube analysis
|
|
486
|
+
shell: bash
|
|
487
|
+
env:
|
|
488
|
+
GITHUB_TOKEN: ${{ inputs.github-token }}
|
|
489
|
+
SONAR_TOKEN: ${{ inputs.sonar-token }}
|
|
490
|
+
HEAD_REF: ${{ github.head_ref }}
|
|
491
|
+
BASE_REF: ${{ github.base_ref }}
|
|
492
|
+
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
493
|
+
run: |
|
|
494
|
+
SCANNER_ARGS="-Dsonar.host.url=${{ inputs.sonar-host-url }}"
|
|
495
|
+
|
|
496
|
+
# Add PR-specific parameters
|
|
497
|
+
if [ -n "$PR_NUMBER" ]; then
|
|
498
|
+
SCANNER_ARGS="$SCANNER_ARGS \
|
|
499
|
+
-Dsonar.pullrequest.key=${PR_NUMBER} \
|
|
500
|
+
-Dsonar.pullrequest.branch=${HEAD_REF} \
|
|
501
|
+
-Dsonar.pullrequest.base=${BASE_REF}"
|
|
502
|
+
fi
|
|
503
|
+
|
|
504
|
+
sonar-scanner $SCANNER_ARGS
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
**Add to CI workflow** (`.github/workflows/ci.yml`):
|
|
508
|
+
|
|
509
|
+
```yaml
|
|
510
|
+
jobs:
|
|
511
|
+
# Run SonarQube code quality analysis
|
|
512
|
+
sonarqube:
|
|
513
|
+
name: SonarQube Analysis
|
|
514
|
+
runs-on: ubuntu-latest
|
|
515
|
+
needs: [lint, typecheck, test]
|
|
516
|
+
if: github.event_name == 'pull_request' && secrets.SONAR_TOKEN != ''
|
|
517
|
+
steps:
|
|
518
|
+
- name: Checkout code
|
|
519
|
+
uses: actions/checkout@v4
|
|
520
|
+
with:
|
|
521
|
+
fetch-depth: 0 # Full history for better analysis
|
|
522
|
+
|
|
523
|
+
- name: Setup Bun
|
|
524
|
+
uses: oven-sh/setup-bun@v2
|
|
525
|
+
with:
|
|
526
|
+
bun-version: latest
|
|
527
|
+
|
|
528
|
+
- name: Install dependencies
|
|
529
|
+
run: bun install --frozen-lockfile
|
|
530
|
+
|
|
531
|
+
- name: Run tests with coverage
|
|
532
|
+
run: bun test --coverage
|
|
533
|
+
|
|
534
|
+
- name: Run SonarQube analysis
|
|
535
|
+
uses: ./.github/actions/sonar
|
|
536
|
+
with:
|
|
537
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
538
|
+
sonar-token: ${{ secrets.SONAR_TOKEN }}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### GoTask Integration
|
|
542
|
+
|
|
543
|
+
**Create task file** (`tasks/sonar.yml`):
|
|
544
|
+
|
|
545
|
+
```yaml
|
|
546
|
+
version: "3"
|
|
547
|
+
|
|
548
|
+
vars:
|
|
549
|
+
SONAR_HOST: '{{.SONAR_HOST | default "https://sonarcloud.io"}}'
|
|
550
|
+
|
|
551
|
+
tasks:
|
|
552
|
+
download:
|
|
553
|
+
desc: Download SonarQube analysis results
|
|
554
|
+
dotenv: [".env"]
|
|
555
|
+
cmds:
|
|
556
|
+
- |
|
|
557
|
+
# Read project key from sonar-project.properties
|
|
558
|
+
PROJECT_KEY=$(grep "^sonar.projectKey=" sonar-project.properties | cut -d'=' -f2)
|
|
559
|
+
|
|
560
|
+
# Detect PR context
|
|
561
|
+
PR_NUMBER=$(gh pr list --head "$(git branch --show-current)" --json number --jq '.[0].number' 2>/dev/null || echo "")
|
|
562
|
+
|
|
563
|
+
# Fetch issues from SonarQube API
|
|
564
|
+
if [ -n "$PR_NUMBER" ]; then
|
|
565
|
+
ISSUES_API="{{.SONAR_HOST}}/api/issues/search?pullRequest=$PR_NUMBER&componentKeys=$PROJECT_KEY&ps=500"
|
|
566
|
+
else
|
|
567
|
+
ISSUES_API="{{.SONAR_HOST}}/api/issues/search?componentKeys=$PROJECT_KEY&ps=500"
|
|
568
|
+
fi
|
|
569
|
+
|
|
570
|
+
curl -s -X GET "$ISSUES_API" -H "Authorization: Bearer $SONAR_TOKEN" > .logs/sonar/issues.json
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
## Best Practices
|
|
574
|
+
|
|
575
|
+
### For AI Agents
|
|
576
|
+
|
|
577
|
+
**Always use task commands:**
|
|
578
|
+
|
|
579
|
+
```bash
|
|
580
|
+
# ✓ GOOD - Use task commands (logged, cached, consistent)
|
|
581
|
+
task sonar:download
|
|
582
|
+
|
|
583
|
+
# ✗ BAD - Direct API calls (no caching, harder to debug)
|
|
584
|
+
curl -X GET "https://sonarcloud.io/api/issues/search?..." -H "Authorization: Bearer $SONAR_TOKEN"
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
**Check for SonarQube setup before using:**
|
|
588
|
+
|
|
589
|
+
```typescript
|
|
590
|
+
// Check if sonar-project.properties exists
|
|
591
|
+
const hasSonar = existsSync("sonar-project.properties");
|
|
592
|
+
|
|
593
|
+
if (!hasSonar) {
|
|
594
|
+
console.log("⚠️ SonarQube not configured in this repository");
|
|
595
|
+
return; // Skip SonarQube analysis
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Proceed with analysis
|
|
599
|
+
await bash("task sonar:download");
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**Parse reports programmatically:**
|
|
603
|
+
|
|
604
|
+
```typescript
|
|
605
|
+
// Read downloaded report
|
|
606
|
+
const report = readFileSync(".logs/sonar/issues-20251118-115543.txt", "utf-8");
|
|
607
|
+
|
|
608
|
+
// Extract issues by pattern matching
|
|
609
|
+
const blockers = report
|
|
610
|
+
.split("\n")
|
|
611
|
+
.filter((line) => line.startsWith("[BLOCKER]"))
|
|
612
|
+
.map((line) => parseIssueLine(line));
|
|
613
|
+
|
|
614
|
+
// Fix each issue
|
|
615
|
+
for (const issue of blockers) {
|
|
616
|
+
await fixIssue(issue);
|
|
617
|
+
}
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
**Document all suppressions:**
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
// ALWAYS add explanation for suppressions
|
|
624
|
+
// ✓ GOOD
|
|
625
|
+
// SECURITY: Test fixture with fake GitHub token format, not a real secret
|
|
626
|
+
// nosemgrep: generic.secrets.security.detected-generic-secret.detected-generic-secret
|
|
627
|
+
const token = "github_pat_test123";
|
|
628
|
+
|
|
629
|
+
// ✗ BAD
|
|
630
|
+
// nosemgrep: generic.secrets.security.detected-generic-secret.detected-generic-secret
|
|
631
|
+
const token = "github_pat_test123";
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
**Prioritize fixes:**
|
|
635
|
+
|
|
636
|
+
1. **BLOCKER**: Fix immediately (breaks core functionality)
|
|
637
|
+
2. **HIGH security hotspots**: Review and fix real vulnerabilities
|
|
638
|
+
3. **CRITICAL**: Fix after blockers
|
|
639
|
+
4. **MEDIUM/LOW hotspots**: Document false positives, defer real issues
|
|
640
|
+
5. **MAJOR/MINOR**: Address in follow-up PRs
|
|
641
|
+
|
|
642
|
+
### For Repository Maintainers
|
|
643
|
+
|
|
644
|
+
**Quality gate targets:**
|
|
645
|
+
|
|
646
|
+
- **Coverage**: ≥80% code coverage
|
|
647
|
+
- **Duplication**: ≤3% duplicated code
|
|
648
|
+
- **Security**: 0 vulnerabilities, 0 HIGH hotspots
|
|
649
|
+
- **Maintainability**: No BLOCKER/CRITICAL code smells
|
|
650
|
+
|
|
651
|
+
**Custom quality gates:**
|
|
652
|
+
|
|
653
|
+
Edit in SonarCloud UI → Project → Administration → Quality Gate
|
|
654
|
+
|
|
655
|
+
**Branch protection:**
|
|
656
|
+
|
|
657
|
+
Require SonarQube check to pass before merging:
|
|
658
|
+
|
|
659
|
+
1. GitHub → Settings → Branches
|
|
660
|
+
2. Add rule for `main` branch
|
|
661
|
+
3. Check "Require status checks to pass"
|
|
662
|
+
4. Select "SonarQube Analysis"
|
|
663
|
+
|
|
664
|
+
## Troubleshooting
|
|
665
|
+
|
|
666
|
+
### Token Not Set
|
|
667
|
+
|
|
668
|
+
**Error:**
|
|
669
|
+
|
|
670
|
+
```text
|
|
671
|
+
❌ SONAR_TOKEN not set
|
|
672
|
+
Add to .env: SONAR_TOKEN=your-token
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**Solution:**
|
|
676
|
+
|
|
677
|
+
```bash
|
|
678
|
+
# Add to .env file (gitignored)
|
|
679
|
+
echo "SONAR_TOKEN=your-token-here" >> .env
|
|
680
|
+
|
|
681
|
+
# Or use 1Password
|
|
682
|
+
echo "SONAR_TOKEN=op://Private/SonarCloud/API Token/token" >> .env
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
### No Reports Found
|
|
686
|
+
|
|
687
|
+
**Error:**
|
|
688
|
+
|
|
689
|
+
```text
|
|
690
|
+
❌ No reports found
|
|
691
|
+
Run: task sonar:download
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
**Solution:**
|
|
695
|
+
|
|
696
|
+
```bash
|
|
697
|
+
# Download analysis first
|
|
698
|
+
task sonar:download
|
|
699
|
+
|
|
700
|
+
# Then view results
|
|
701
|
+
task sonar:issues
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### PR Analysis Not Found
|
|
705
|
+
|
|
706
|
+
**Warning:**
|
|
707
|
+
|
|
708
|
+
```text
|
|
709
|
+
⚠️ PR analysis not found, showing default branch analysis
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
**Why:** SonarQube PR analysis only runs after CI completes. If viewing results before CI finishes, default branch analysis is shown instead.
|
|
713
|
+
|
|
714
|
+
**Solution:** Wait for CI to complete, then run `task sonar:download` again.
|
|
715
|
+
|
|
716
|
+
### Quality Gate Failed
|
|
717
|
+
|
|
718
|
+
**Error:**
|
|
719
|
+
|
|
720
|
+
```text
|
|
721
|
+
❌ Quality Gate: ERROR
|
|
722
|
+
Failed Conditions:
|
|
723
|
+
- coverage: 65.2% (threshold: 80%)
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
**Solution:**
|
|
727
|
+
|
|
728
|
+
```bash
|
|
729
|
+
# Check what needs to be fixed
|
|
730
|
+
task sonar:download
|
|
731
|
+
|
|
732
|
+
# Fix coverage
|
|
733
|
+
bun test --coverage
|
|
734
|
+
|
|
735
|
+
# Fix duplication
|
|
736
|
+
# (Refactor duplicated code blocks)
|
|
737
|
+
|
|
738
|
+
# Re-run analysis
|
|
739
|
+
task sonar:scan
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### sonar-scanner Not Found
|
|
743
|
+
|
|
744
|
+
**Error:**
|
|
745
|
+
|
|
746
|
+
```text
|
|
747
|
+
sonar-scanner: command not found
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**Solution:**
|
|
751
|
+
|
|
752
|
+
```bash
|
|
753
|
+
# Install sonar-scanner
|
|
754
|
+
task sonar:setup
|
|
755
|
+
|
|
756
|
+
# Verify installation
|
|
757
|
+
sonar-scanner --version
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
## Examples
|
|
761
|
+
|
|
762
|
+
### Example 1: Fix All Blocker Issues
|
|
763
|
+
|
|
764
|
+
```bash
|
|
765
|
+
# Download analysis
|
|
766
|
+
task sonar:download
|
|
767
|
+
|
|
768
|
+
# Read report
|
|
769
|
+
REPORT=$(ls -t .logs/sonar/issues-*.txt | head -1)
|
|
770
|
+
|
|
771
|
+
# Extract blocker issues
|
|
772
|
+
grep "^\[BLOCKER\]" "$REPORT" | while read -r line; do
|
|
773
|
+
# Parse file and line number
|
|
774
|
+
FILE=$(echo "$line" | sed 's/\[BLOCKER\] \(.*\):.*/\1/')
|
|
775
|
+
LINE=$(echo "$line" | sed 's/.*:\([0-9]*\).*/\1/')
|
|
776
|
+
|
|
777
|
+
echo "Fixing $FILE:$LINE"
|
|
778
|
+
|
|
779
|
+
# Open in editor or apply automated fix
|
|
780
|
+
# ... implementation ...
|
|
781
|
+
done
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
### Example 2: Review Security Hotspots by Priority
|
|
785
|
+
|
|
786
|
+
```bash
|
|
787
|
+
# Download analysis
|
|
788
|
+
task sonar:download
|
|
789
|
+
|
|
790
|
+
# Find HIGH priority hotspots in report
|
|
791
|
+
REPORT=$(ls -t .logs/sonar/issues-*.txt | head -1)
|
|
792
|
+
|
|
793
|
+
# Extract HIGH severity hotspots
|
|
794
|
+
grep -A3 "^\[HIGH\]" "$REPORT" | while read -r line; do
|
|
795
|
+
case "$line" in
|
|
796
|
+
\[HIGH\]*)
|
|
797
|
+
FILE=$(echo "$line" | sed 's/\[HIGH\] \(.*\):.*/\1/')
|
|
798
|
+
echo "Review: $FILE"
|
|
799
|
+
;;
|
|
800
|
+
Message:*)
|
|
801
|
+
echo " → ${line#Message: }"
|
|
802
|
+
;;
|
|
803
|
+
esac
|
|
804
|
+
done
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
### Example 3: Track Fix Progress
|
|
808
|
+
|
|
809
|
+
```typescript
|
|
810
|
+
// Track fixes in PR review documentation
|
|
811
|
+
interface FixProgress {
|
|
812
|
+
total: number;
|
|
813
|
+
fixed: number;
|
|
814
|
+
remaining: number;
|
|
815
|
+
categories: {
|
|
816
|
+
blocker: number;
|
|
817
|
+
critical: number;
|
|
818
|
+
hotspots: { high: number; medium: number; low: number };
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
async function trackProgress(): Promise<FixProgress> {
|
|
823
|
+
// Download latest analysis
|
|
824
|
+
await bash("task sonar:download");
|
|
825
|
+
|
|
826
|
+
// Read report
|
|
827
|
+
const report = readFileSync(".logs/sonar/issues-latest.txt", "utf-8");
|
|
828
|
+
|
|
829
|
+
// Count by severity
|
|
830
|
+
const blockers = (report.match(/^\[BLOCKER\]/gm) || []).length;
|
|
831
|
+
const criticals = (report.match(/^\[CRITICAL\]/gm) || []).length;
|
|
832
|
+
const highHotspots = (report.match(/^\[HIGH\].*hotspot/gim) || []).length;
|
|
833
|
+
|
|
834
|
+
return {
|
|
835
|
+
total: blockers + criticals + highHotspots,
|
|
836
|
+
fixed: 0, // Updated as fixes are applied
|
|
837
|
+
remaining: blockers + criticals + highHotspots,
|
|
838
|
+
categories: {
|
|
839
|
+
blocker: blockers,
|
|
840
|
+
critical: criticals,
|
|
841
|
+
hotspots: { high: highHotspots, medium: 0, low: 0 },
|
|
842
|
+
},
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
## Related Documentation
|
|
848
|
+
|
|
849
|
+
- [GoTask Usage Guide](./agents.gotask.md) - Task automation patterns
|
|
850
|
+
- [Markdown Standards](./agents.markdown.md) - Documentation formatting
|
|
851
|
+
- [GitHub MCP Integration](./github-mcp.md) - PR and issue management
|
|
852
|
+
- [QA Standards](../QA.md) - Quality assurance guidelines
|
|
853
|
+
- [SonarCloud Documentation](https://docs.sonarcloud.io) - Official docs
|
|
854
|
+
|
|
855
|
+
---
|
|
856
|
+
|
|
857
|
+
**For AI Agents**: Always use `task sonar:download` to fetch analysis results programmatically. Never require manual UI access. Parse downloaded reports to address findings automatically.
|