SonarQube:持续代码质量与安全扫描
bash
docker run -d --name sonarqube
-p 9000:9000
-e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true
sonarqube:lts-community
> **说明**:`-e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true` 是避免某些环境下 Elasticsearch 内存检查失败。生产环境请勿使用此参数,而是通过 `-e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true` 配置合理的内核参数。
### 步骤2:访问 Web UI
容器启动需要几分钟,等待日志出现 “SonarQube is operational” 后,访问 `http://localhost:9000`。默认账号密码为 `admin` / `admin`,首次登录后会强制修改密码。
### 步骤3:创建本地项目并生成令牌
登录后,你可以选择手动创建项目或稍后在扫描时自动创建。推荐流程:
1. 点击顶部导航 “Projects” -> “Create Project”。
2. 输入项目显示名称和项目标识符(Key),点击 “Set Up”。
3. 在 “Provide a token” 步骤,选择 “Generate a token”,输入令牌名称(如 `my-local-token`),点击 “Generate” 并**立即复制保存**,这个令牌只显示一次。
4. 继续,选择项目的主要语言和构建技术(如 Maven、Gradle、Other(JS/TS)等),页面会给出具体的扫描命令,后面会用到。
## 执行第一次代码扫描
SonarQube 的扫描是通过扫描器(Scanner)完成的。扫描器在客户端运行,分析代码后将结果推送到 SonarQube 服务器。
### 对于通用项目使用 SonarScanner CLI
这是最灵活的方式,适用于几乎所有语言。
#### 1. 下载并配置 Scanner
从 [SonarScanner CLI 下载页面](https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/) 获取对应操作系统的压缩包,解压后将其 `bin` 目录添加到系统 PATH 中。
你也可以使用 Docker 一键扫描(无需本地安装):
```bash
docker run \
--rm \
--network host \
-e SONAR_HOST_URL="http://localhost:9000" \
-e SONAR_TOKEN="你的项目令牌" \
-v "你的项目绝对路径:/usr/src" \
sonarsource/sonar-scanner-cli
2. 在项目根目录创建 sonar-project.properties
如果你想手动配置扫描参数,可以创建此文件:
# 必须唯一,对应 SonarQube 中项目的 Key
sonar.projectKey=my-awesome-project
# 项目名称,在 UI 中显示
sonar.projectName=My Awesome Project
# 项目版本
sonar.projectVersion=1.0
# 源码目录,逗号分隔多个路径
sonar.sources=src
# 编译后的 class 文件目录(Java 等需要)
sonar.java.binaries=target/classes
# 排除某些文件
sonar.exclusions=**/test/**, **/*.spec.ts
# 编码格式
sonar.sourceEncoding=UTF-8
3. 运行扫描命令
在项目根目录下执行:
sonar-scanner \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.token=你的项目令牌
或者如果已有属性文件,且环境变量已设置:
export SONAR_HOST_URL=http://localhost:9000
export SONAR_TOKEN=你的令牌
sonar-scanner
扫描完成后,回到 SonarQube Web UI,刷新项目页,你就能看到详细的代码质量报告。
对于 Maven/Gradle 项目的一键扫描
如果使用构建工具,集成更简单,无需单独下载 Scanner。
Maven 项目:
确保 mvn 命令可用,在项目根目录执行:
mvn clean verify sonar:sonar \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.token=你的令牌
Gradle 项目:
在 build.gradle 中添加插件:
plugins {
id "org.sonarqube" version "4.4.1.3373"
}
然后运行:
gradle sonarqube \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.token=你的令牌
读懂 SonarQube 报告与质量门
扫描后的仪表板是核心,理解这些指标才能让 SonarQube 发挥作用。
整体质量视图
进入项目主页,你会看到几个关键块:
- 质量门状态:绿色通过(Passed)或红色失败(Failed)。如果配置了条件并失败,说明代码未达到标准。
- Bug & 漏洞:显示静态分析发现的错误和安全风险数量,按严重程度着色。
- 代码异味:与可维护性相关的问题,右侧会估算“技术债务”时间。例如 “10h” 表示修复所有异味预计需要 10 小时。
- 覆盖率:显示由单元测试覆盖的代码行百分比。如果未集成测试报告,则为 0% 或 N/A。
- 重复:重复代码块的百分比。通常建议保持在 3% 以下。
- 代码行数、复杂度等统计信息。
深入问题列表
点击 “Issues” 标签,你可以看到所有检测出的问题列表。这里可以进行高级筛选:
- 严重级别:Blocker(阻断)、Critical(严重)、Major(主要)、Minor(次要)、Info(提示)。
- 类型:Bug、Vulnerability、Code Smell。
- 状态:Open(未解决)、Confirmed(已确认)、False Positive(误报)、Won't Fix(不予修复)。
- 指派:可以将问题分配给具体开发者。
- 标签:按规则分类(如
cwe,security,performance)。
点击具体问题,右侧会显示详细说明、所在代码位置,以及为什么这是一个问题、如何修复,甚至给出符合规则的代码示例。这是新手学习和团队规范统一的绝佳资源。
自定义质量门
默认的质量门 “Sonar way” 是官方推荐的起点。你可以创建自己的质量门以匹配团队标准。
- 顶部导航点击 “Quality Gates”,然后点击 “Create”。
- 输入名称(如 “My strict gate”),点击“Add Condition”。
- 选择指标,例如:
- On New Code(推荐,只关注新增代码的质量,避免历史债务干扰)
Coverage:新代码覆盖率小于 80% 则标记失败。Blocker Issues:新代码阻断问题 > 0 则失败。
- Overall Code(全局代码)
Technical Debt Ratio:技术债务比率超过 5% 失败。
- On New Code(推荐,只关注新增代码的质量,避免历史债务干扰)
- 将项目添加到该质量门下,在质量门设置页面点击 “Projects” 选项卡,添加到指定项目。
与 CI/CD 集成:自动化质量保障
将 SonarQube 扫描融入流水线,才能真正实现“持续”质量检查。以下以 GitLab CI 和 GitHub Actions 为例。
GitLab CI 集成示例
在 .gitlab-ci.yml 中加入扫描步骤:
stages:
- test
- sonarqube-check
sonarqube-check:
stage: sonarqube-check
image:
name: sonarsource/sonar-scanner-cli:latest
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # 防止缓存冲突
GIT_DEPTH: "0" # 完整 git 历史获取,用于新代码分析
script:
- sonar-scanner
-Dsonar.projectKey=$CI_PROJECT_NAME
-Dsonar.sources=.
-Dsonar.host.url=$SONAR_HOST_URL
-Dsonar.token=$SONAR_TOKEN
allow_failure: true # 或 false,取决于你是否要阻断流水线
注意:需要在 GitLab 项目的 CI/CD 变量中设置
SONAR_HOST_URL和SONAR_TOKEN。
GitHub Actions 示例
在仓库的 .github/workflows/sonarqube.yml 中:
name: SonarQube Scan
on:
push:
branches: [ main ]
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarqube:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@v2
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
使用官方的 GitHub Action,无需手动安装 Scanner。同样配置 Secrets。
提升扫描价值:集成测试覆盖率与外部报告
只进行静态分析还不够,结合测试覆盖率才能全面衡量。
集成 JaCoCo(Java)报告
Maven 项目通常使用 JaCoCo 插件生成报告:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.11</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
然后执行 mvn clean verify,报告默认生成在 target/site/jacoco/jacoco.xml。你在执行 sonar:sonar 时,需要设置参数指向报告:
mvn sonar:sonar \
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
集成 JavaScript/TypeScript 覆盖率(Istanbul)
如果你使用 Jest 或类似测试框架,先确保配置生成 lcov.info 格式的报告。在 package.json 中配置 Jest:
{
"jest": {
"collectCoverage": true,
"coverageReporters": ["lcov"]
}
}
然后在 sonar-project.properties 中指定路径:
sonar.javascript.lcov.reportPaths=coverage/lcov.info
集成第三方安全报告(可选)
SonarQube 还能导入其他安全工具的 SARIF 报告,通过 sonar.externalIssuesReportPaths 属性集成,例如:
sonar.externalIssuesReportPaths=bandit-report.json,eslint-report.json