全量代码检查方案
本指南面向在 GitCode 平台落地分支全量代码检查、并期望使用 openLiBing 实现问题可视化的团队。方案覆盖检查场景定义、openLiBing 结果可视化、按语言的工具选型、以及每个工具在 pre-commit 集成与工具单独使用(workflow)两种接入方式之间如何选择的对比分析;已落地的工具使用文档见 下级 tools 目录。
1. 方案背景与目标
1.1 三种检查场景
团队代码检查通常存在三种场景,本方案聚焦"分支全量检查":
| 场景 | 触发方式 | 现状 | 时限要求 |
|---|---|---|---|
| 本地检查 | 开发者提交前(git hook) | 已通过 pre-commit 框架集成各类工具 | ≤ 10 分钟(针对 pre-commit) |
| PR 检查 | Pull Request 事件 | 已通过 pre-commit 框架集成 | ≤ 10 分钟(针对 pre-commit) |
| 分支全量 | 代码仓 action 流水线(push / 定时 / 手动) | 本方案建设目标 | 原则上无整体硬性时限,尽量控制在小时级 |
时限语义:10 分钟时限仅针对本地/PR 场景的 pre-commit 执行;分支全量场景无整体硬性时限,目标是尽量控制在小时级、尽可能短,通过并行、缓存等手段优化。
1.2 本方案目标
- 覆盖 C / C++ / Python / Go / Java / Rust / JS / TS 等主流语言的静态检查与安全扫描;
- 分支全量检查依托 GitCode CI 流水线执行,支持 push、定时、手动等事件触发;
- 工具范围包括 pre-commit 内已集成的工具 + 因耗时/环境原因移出 pre-commit 的额外工具(接入方式的选择见 4.1 方案对比与选择指引);
- 各工具扫描结果统一转换为 SARIF 格式,上传 openLiBing 平台可视化;
- 同时适配 monorepo(单仓多语言) 与 多仓(各仓单语言) 两种形态。
2. 结果可视化:openLiBing 代码检查页面说明
所有工具(无论 pre-commit 集成还是 workflow 单独使用)的扫描结果统一归一为 SARIF v2.1.0 并上传 openLiBing 平台,最终在「开发管理 - 代码检查」模块按工具名区分展示。
为什么选 SARIF v2.1.0:SARIF(Static Analysis Results Interchange Format,静态分析结果交换格式)是由 OASIS 标准组织维护的开放标准,用于在不同静态分析工具与平台之间交换扫描结果。各工具原生输出格式各异(文本 / XML / 自定义 JSON 等),统一归一为 SARIF 后可获得:
- 格式统一:openLiBing 只需实现一种解析器即可接入全部工具,避免逐工具定制适配;
- 信息完整:结构化承载规则(rule)、级别(level)、位置(file / line / column)与 fingerprint 等字段,支持问题去重与追踪;
- 生态互通:GitHub Code Scanning、VS Code 等主流平台原生支持 SARIF,结果可平滑复用与对接。
版本说明:SARIF v2.1.0 于 2020 年 3 月被批准为 OASIS 标准,是当前主流工具(SpotBugs、ESLint、gosec 等)及转换器(如
eslint-formatter-sarif、clang-tidy-sarif、clippy-sarif)默认输出/解析的基准版本;本方案(含 openLiBing 解析端)均以 v2.1.0 为契约基准。官方文档:
2.1 查看问题列表

2.2 查看问题详情

说明:openLiBing 页面为各工具共用,SpotBugs 等不同工具的结果均在该页面按工具名区分展示,页面操作方式一致。
3. 工具选型:不同语言的检查工具
3.1 语言 × 工具选型矩阵
下表为主流语言的推荐工具及其典型特征(前置条件、SARIF 能力),用于新仓库接入时的初始选型预判:
| 语言 | 工具 | 前置条件 | SARIF 能力 | 使用文档 |
|---|---|---|---|---|
| 密钥 | gitleaks | 无 | 原生:--report-format sarif |
使用文档 |
| Python | bandit | pip 安装 | 原生:-f sarif |
使用文档 |
| Go | gosec | Go 工具链 | 原生:-fmt sarif |
使用文档 |
| JS/TS | ESLint(含 typescript-eslint) | npm 安装 | 转换器:@microsoft/eslint-formatter-sarif |
使用文档 |
| C/C++ | clang-tidy | compile_commands.json(cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON) |
转换器:clang-tidy-sarif(psastras/sarif-rs) |
使用文档 |
| Rust | rust-clippy | Rust 工具链 + cargo clippy;clippy-sarif 转换器(cargo install clippy-sarif) |
转换器:clippy-sarif(cargo clippy --message-format=json | clippy-sarif) |
使用文档 |
| Java | SpotBugs | 编译字节码(maven/gradle 构建先行) | 原生:SARIF 输出参数 | 使用文档 |
| 多语言 | CodeArts Check(云端服务) | 华为云 CodeArts 项目与检查任务 + AK/SK Secrets | 插件:CodeArts Check API 拉取问题明细转 SARIF | 使用文档 |
📌 已落地的工具使用文档见 下级 tools 目录,其余工具文档陆续补充中。
4. 全量检查配置方案
4.1 方案对比与选择指引
本方案提供两种接入方式:pre-commit 集成(通过 .pre-commit-config.yaml 统一声明工具,本地提交前拦截,流水线可用 pre-commit-action 复用同一配置)与 workflow 单独使用(每个/每组工具配置独立 job,流水线直接扫描并上传)。两者不是二选一的对立关系,可并存互补:
| 维度 | 方案一:pre-commit 集成 | 方案二:workflow 单独使用 |
|---|---|---|
| 性能 | ≤ 10 分钟时限,快速反馈 | 无整体硬性时限,可并行 + 缓存,目标小时级 |
| 运行环境 | 开发者本机需安装 pre-commit 及工具链;流水线执行机需能访问 hook 仓库(GitHub 或 GitCode 镜像)与工具依赖 | 统一在流水线执行机上运行,工具链通过 setup-* action 安装指定版本,环境可控 |
| 编译依赖 | 以轻量工具为主,需编译的工具仅小仓库可容纳 | 可承载需编译产物 / 构建的工具(clang-tidy、SpotBugs、rust-clippy) |
| 适合工具 | 轻量、支持按文件扫描的工具(gitleaks、bandit、gosec、ESLint 等) | 需编译产物 / 构建 / 耗时长而移出 pre-commit 的工具 |
选择指引:核心判定依据是该工具在你仓库中的实测检查耗时与环境依赖:
- 耗时预算:本地/PR 场景 pre-commit 总时限 10 分钟。某工具全量执行明显挤占预算(单工具超过总预算 1/3,或拖累整体逼近 10 分钟)→ 移出 pre-commit,改为 workflow 单独执行;
- 环境依赖:工具链版本、编译数据库等条件在本机 / 流水线执行机无法稳定满足,pre-commit 内无法可靠运行 → 改为 workflow 单独执行;
- 其余能在时限内稳定完成的工具 → 留在 pre-commit。
💡 接入方式归属是动态的,可随仓库规模变化迁移:调整
.pre-commit-config.yaml(移入/移出钩子)+ 增删对应流水线 job 即可。迁移不改变全量检查范围——无论工具走哪种接入方式,其结果都应归一为 SARIF 上传 openLiBing,避免遗漏。
4.2 方案一:pre-commit 集成(全量配置样例)
通过 .pre-commit-config.yaml 统一声明检查工具,本地 git commit 前触发拦截;在流水线中由 pre-commit-action 插件执行同一套配置(非 PR 事件检查全量)并生成/收集 SARIF,再由 upload-sarif-action 插件上传 openLiBing。
完整配置见 pre-commit 落地指南。
4.2.1 全量 .pre-commit-config.yaml 样例(含全部工具,按需删减)
以下是一份包含本方案全部 7 个工具的完整 .pre-commit-config.yaml。接入时按你的仓库语言保留对应 repos/hooks 段,删除其余即可;也可在保留段内微调参数。各工具的参数说明与 FAQ 见对应工具文档。
# .pre-commit-config.yaml —— 全量代码检查(方案一:pre-commit 集成)
# 用法:按仓库语言保留需要的 hooks 段,删除其余;每段顶部注释标明适用语言与依赖
# 通用钩子(trailing-whitespace 等)已由 GitCode CI 流水线自带或本地 git hook 覆盖,无需重复配置
repos:
# ===================== 敏感信息扫描(全语言) =====================
# gitleaks:检测硬编码密钥、Token、密码等敏感信息(GitCode 自建仓 wrapper 自动下载二进制,无需装 Go)
- repo: https://gitcode.com/GitHub_Trending/gi/gitleaks
rev: v8.30.1
hooks:
- id: gitleaks
# ===================== Python =====================
# bandit:Python 安全扫描(检出所有级别问题;正式启用可收紧为 args: ["-ll"])
- repo: https://gitcode.com/gh_mirrors/ba/bandit
rev: 1.9.4
hooks:
- id: bandit
# ===================== Go =====================
# gosec:Go 安全扫描(local hook,依赖流水线/本机预装 .gitcode/bin/gosec)
- repo: local
hooks:
- id: gosec
name: gosec (sarif report)
entry: .gitcode/bin/gosec
language: system
types: [go]
pass_filenames: false
require_serial: true
args:
- -conf=gosec.json
- -fmt=sarif
- -out=/tmp/pre-commit-reports/gosec.sarif
- -exclude-dir=vendor
- -exclude-generated
- ./...
# ===================== JS/TS =====================
# ESLint:JS/TS Lint(local hook,依赖 node_modules 已安装 + SARIF formatter)
- repo: local
hooks:
- id: eslint
name: eslint (sarif report)
entry: ./node_modules/.bin/eslint
language: system
files: ^src/.*\.(js|ts)$
require_serial: true
args:
- --format
- "@microsoft/eslint-formatter-sarif"
- --output-file
- /tmp/pre-commit-reports/eslint.sarif
- --no-error-on-unmatched-pattern
# ===================== C/C++ =====================
# clang-tidy:C/C++ 静态检查(local hook,依赖本机 clang-tidy + build/compile_commands.json + scripts/run-clang-tidy.py)
- repo: local
hooks:
- id: clang-tidy
name: clang-tidy check
language: system
entry: python3 scripts/run-clang-tidy.py
pass_filenames: false
types_or: [c, c++]
# ===================== Rust =====================
# cargo-clippy:Rust 静态检查(local hook,扫描与 SARIF 转换内联在 entry,依赖本机 Rust 工具链 + clippy-sarif)
# - 两次执行 cargo clippy:第一次人类可读输出 + 捕获退出码 rc 决定拦截;第二次 --message-format=json | clippy-sarif 生成 SARIF
- repo: local
hooks:
- id: cargo-clippy
name: cargo-clippy check
language: system
entry: bash -c 'set -o pipefail; mkdir -p /tmp/clippy-result; cargo clippy ; rc=$?; cargo clippy --message-format=json | clippy-sarif > /tmp/clippy-result/clippy-results.sarif; exit $rc'
pass_filenames: false # cargo 不接受文件名参数,只在工作区根目录整体运行
files: '(^|/)(Cargo\.toml|Cargo\.lock|[^/]+\.rs)$' # 仅 Rust 相关文件变更时触发
require_serial: true # 串行运行,避免 cargo 锁冲突
verbose: true # 通过时也输出人类可读的 clippy 结果,否则 pre-commit 只显示 Passed
# ===================== Java =====================
# SpotBugs:Java 字节码分析(local hook,依赖 mvn + pom.xml 插件配置,见工具文档 2.3)
- repo: local
hooks:
- id: mvn-spotbugs
name: Maven SpotBugs Check
language: system
entry: mvn compile spotbugs:check
pass_filenames: false
📌 工具文档中「场景一 .pre-commit-config.yaml 配置」小节给出的是单工具片段,本文档 4.2.1 是全量合并版;两者任一形式都可直接使用。各工具的规则配置文件(gosec.json / .clang-tidy / .gitleaks.toml / eslint.config.mjs 等)仍需按工具文档放置在仓库对应位置。
4.2.2 配套流水线样例(pre-commit-action 执行全量钩子 + upload-sarif-action 上传)
本地提交前由 pre-commit 拦截;如需在流水线中执行同一份配置并上传 SARIF,分两步:先由 openlibing/pre-commit-action@v1.0.0 执行钩子并生成/收集 SARIF(输出 sarif-files),再由 openlibing/upload-sarif-action@v1.0.0 读取报告上传 OBS + 回调 openLiBing:
name: pre-commit-report
on:
workflow_dispatch:
push:
branches: ["main"]
permissions:
repository: read
id-token: write # pre-commit-action 插件 OIDC 免密换证必需
# 工具链版本统一固定,保证 CI 环境可复现(cargo-clippy 钩子依赖)
env:
RUST_TOOLCHAIN: "1.98.1" # 含 rustc / cargo / clippy(clippy 随工具链版本发布)
CLIPPY_SARIF: "0.8.0" # clippy JSON -> SARIF 转换工具
jobs:
pre-commit-report:
name: pre-commit-report
runs-on: ["codearts-hosted", "ubuntu-latest", "x64", "slim"]
steps:
- name: Checkout repository
uses: checkout
- name: setup-python
uses: setup-python
with:
version: 3.14
cache: true
# ---- 工具链准备:与 .pre-commit-config.yaml 保留的钩子一一对应,按需删减 ----
# gosec:安装到仓库 .gitcode/bin/
- name: setup-go
uses: setup-go
with:
version: "1.23"
cache: true
- name: Install gosec
env:
GOPROXY: https://goproxy.cn,https://goproxy.io,direct
GOSUMDB: sum.golang.google.cn
run: |
mkdir -p .gitcode/bin /tmp/pre-commit-reports/
GOBIN="$(pwd)/.gitcode/bin" go install github.com/securego/gosec/v2/cmd/gosec@v2.22.4
chmod +x .gitcode/bin/gosec
.gitcode/bin/gosec -version
# ESLint:装 node 依赖 + SARIF formatter
- name: setup-node
uses: setup-node
with:
node-version: "20"
cache: true
- name: Install npm dependencies
run: npm install
- name: Install SARIF formatter
run: npm install --no-save --no-package-lock @microsoft/eslint-formatter-sarif@3.1.0
# clang-tidy:安装工具 + 生成 compile_commands.json
- name: Install clang-tidy
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy
clang-tidy --version
- name: Build CMake compile_commands.json
run: |
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Release
test -f build/compile_commands.json || { echo "ERROR: compile_commands.json not generated"; exit 1; }
# cargo-clippy:安装 Rust 工具链 + clippy 组件 + clippy-sarif(版本固定,幂等)
- name: setup-rust
run: |
export RUSTUP_DIST_SERVER="https://rsproxy.cn"
export RUSTUP_UPDATE_ROOT="https://rsproxy.cn/rustup"
if ! command -v rustup >/dev/null 2>&1 && [ ! -x "$HOME/.cargo/bin/rustup" ]; then
echo "rustup not found, installing..."
curl --proto '=https' --tlsv1.2 -sSf https://rsproxy.cn/rustup-init.sh | \
sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN"
else
echo "rustup already exists, ensure toolchain $RUST_TOOLCHAIN ..."
rustup toolchain install "$RUST_TOOLCHAIN" --no-self-update
rustup default "$RUST_TOOLCHAIN"
fi
. "$HOME/.cargo/env"
rustup --version && cargo --version && rustc --version
echo "$HOME/.cargo/bin" >> "$ATOMGIT_PATH"
- name: install clippy component
run: |
. "$HOME/.cargo/env"
export RUSTUP_DIST_SERVER="https://rsproxy.cn"
export RUSTUP_UPDATE_ROOT="https://rsproxy.cn/rustup"
if rustup component list --installed --toolchain "$RUST_TOOLCHAIN" | grep -q "^clippy"; then
echo "clippy component already installed, skip"
else
rustup component add clippy --toolchain "$RUST_TOOLCHAIN"
fi
- name: install clippy-sarif
run: |
. "$HOME/.cargo/env"
mkdir -p ~/.cargo
cat > ~/.cargo/config.toml <<'EOF'
[source.crates-io]
replace-with = "rsproxy-sparse"
[source.rsproxy-sparse]
registry = "sparse+https://rsproxy.cn/index/"
EOF
if command -v clippy-sarif >/dev/null 2>&1; then
echo "clippy-sarif already installed, skip"
else
cargo install clippy-sarif --version "$CLIPPY_SARIF" --locked
fi
# SpotBugs:JDK + Maven 环境(pom.xml 已声明 spotbugs 插件配置)
- name: setup-jdk
uses: setup-jdk
with:
jdk-version: 21
maven-version: "3.8.9"
# 步骤 1:运行 pre-commit(读取 .pre-commit-config.yaml 执行全部钩子,生成/收集 SARIF)
- name: run pre-commit (generate sarif)
id: pre-commit
uses: openlibing/pre-commit-action@v1.0.0
with:
report-dir: /tmp/pre-commit-reports/
# 步骤 2:上传 SARIF 并回调 openLiBing(OIDC 免密换证)
- name: upload sarif reports
if: ${{ always() }}
uses: openlibing/upload-sarif-action@v1.0.0
with:
sarif_file: ${{ steps.pre-commit.outputs.sarif-files }}
category: "pre-commit-report"
📌 各钩子的 SARIF 产出约定:gitleaks/bandit 由插件日志兜底解析生成
<tool>.sarif;gosec/ESLint 通过钩子args直接输出到report-dir;clang-tidy 由 wrapper 脚本输出;cargo-clippy 由钩子 entry 内联的clippy-sarif输出到/tmp/clippy-result/;SpotBugs 由 pom.xml 配置输出。PR 类型触发只做检查、不上传报告。
4.3 方案二:workflow 集成(全量配置样例)
在 .gitcode/workflows/ 中为每个(或每组)工具配置独立 job,流水线直接执行扫描命令并产出 SARIF,由 openlibing/upload-sarif-action@v1.0.0 插件统一上传 OBS 并回调 openLiBing。
- 执行时机:流水线(push / 定时 / 手动);
- 检查范围:全量;
- 性能:无整体硬性时限,可并行 + 缓存,目标小时级;需构建的工具(clang-tidy、SpotBugs、clippy)耗时是主要长板;
- 环境支持:统一在流水线执行机上运行,工具链通过 setup-* action 安装指定版本,环境可控;
- 适合工具:需编译产物 / 构建 / 耗时长而移出 pre-commit 的工具;
- 结果去向:SARIF 上传 OBS + 回调 openLiBing 可视化。
示例见 SpotBugs workflow 集成 等工具文档。
4.3.1 全量 workflow 样例(含全部工具 job,按需删减)
以下是一份包含全部 7 个工具 job 的完整 workflow(一个文件、多 job 并行)。接入时按仓库语言保留需要的 job,删除其余即可。每个 job 内也可单独调整触发事件、扫描参数、上传 category。各工具 job 的步骤详解见对应工具文档「场景二」章节。
name: full-code-analysis
on:
workflow_dispatch: # 支持在流水线页面手动触发(功能验证用)
push:
branches: ["main"] # 默认分支推送触发
pull_request_target:
branches: ["main"] # 防 fork PR 篡改 workflow
permissions:
repository: read
id-token: write # openlibing/upload-sarif-action@v1.0.0 插件 OIDC 免密换证必需
jobs:
# ===================== 敏感信息扫描(全语言) =====================
gitleaks-scan:
name: Gitleaks 扫描
runs-on: ["codearts-hosted", "ubuntu-latest", "x64", "slim"]
steps:
- name: Checkout
uses: checkout
with:
ref: ${{ atomgit.event.pull_request.merge_commit_sha || atomgit.event.pull_request.head.sha || atomgit.ref }}
- name: setup-go
uses: setup-go
with:
version: 1.26
cache: true
# 从 GitCode 镜像仓克隆 gitleaks 源码并编译安装(已安装则跳过)
- name: Install gitleaks
run: |
if command -v gitleaks &> /dev/null; then
echo "gitleaks already installed, skip build"
else
if [ ! -d /tmp/gitleaks-src ]; then
git clone https://gitcode.com/GitHub_Trending/gi/gitleaks.git /tmp/gitleaks-src
else
echo "/tmp/gitleaks-src already exists, skip clone"
fi
cd /tmp/gitleaks-src
go build -o gitleaks ./cmd/gitleaks
chmod +x gitleaks
mv gitleaks /usr/local/bin/gitleaks
fi
gitleaks version
# 扫描:原生输出 SARIF v2.1.0;检出敏感信息不阻断(失败语义三分离)
- name: 运行 Gitleaks 扫描
run: |
mkdir -p sarif
gitleaks dir . --verbose \
--report-format sarif \
--report-path sarif/gitleaks.sarif \
|| echo "gitleaks found leaks, continuing to upload SARIF"
- name: Upload SARIF to openLiBing
if: ${{ always() }}
uses: openlibing/upload-sarif-action@v1.0.0
with:
sarif_file: sarif/gitleaks.sarif
source_path: .
category: "gitleaks-scan"
# ===================== Python =====================
bandit-scan:
name: Bandit 扫描
runs-on: ["codearts-hosted", "ubuntu-latest", "x64", "slim"]
steps:
- name: Checkout repository
uses: checkout
with:
token: ${{ secrets.ROBOT_TOKEN }}
- name: Install bandit
run: python3 -m pip install "bandit[sarif]" # sarif extra 支持 SARIF 报告格式
# 扫描:不加 -ll 检出所有级别;正式启用可收紧为 -ll(仅 MEDIUM 及以上)
- name: Run bandit scan
run: |
rc=0
bandit -r . -x .gitcode -f sarif -o bandit-report.sarif || rc=$?
if [ "$rc" -ne 0 ]; then
echo "[bandit] scan found issues (exit code $rc); pipeline continues (non-blocking)"
fi
exit 0
- name: Upload SARIF
if: ${{ always() }}
uses: openlibing/upload-sarif-action@v1.0.0
with:
sarif_file: bandit-report.sarif
category: "bandit"
# ===================== Go =====================
gosec-scan:
name: Gosec 扫描
runs-on: ["codearts-hosted", "ubuntu-latest", "x64", "slim"]
steps:
- name: Checkout
uses: checkout
with:
ref: ${{ atomgit.event.pull_request.merge_commit_sha || atomgit.event.pull_request.head.sha || atomgit.ref }}
- name: setup-go
uses: setup-go
with:
version: "1.23"
cache: true
# 安装与扫描同一步,避免 go install 的 PATH 修改无法跨 step 继承
- name: 安装 gosec 并扫描
env:
GOPROXY: https://goproxy.cn,https://goproxy.io,direct
GOSUMDB: sum.golang.google.cn
run: |
export PATH="$PATH:$(go env GOPATH)/bin"
go install github.com/securego/gosec/v2/cmd/gosec@v2.22.4
gosec -version
mkdir -p reports
gosec -no-fail -conf gosec.json -fmt sarif -out reports/gosec.sarif \
-exclude-dir vendor -exclude-generated ./...
- name: Upload SARIF to openLiBing
if: ${{ always() }}
uses: openlibing/upload-sarif-action@v1.0.0
with:
sarif_file: reports/gosec.sarif
source_path: .
category: "gosec-scan"
# ===================== JS/TS =====================
eslint-scan:
name: ESLint 扫描
runs-on: ["codearts-hosted", "ubuntu-latest", "x64", "slim"]
steps:
- name: Checkout
uses: checkout
with:
ref: ${{ atomgit.event.pull_request.merge_commit_sha || atomgit.event.pull_request.head.sha || atomgit.ref }}
- name: setup-node
uses: setup-node
with:
node-version: "20"
cache: true
# 安装仓库依赖 + 单独安装 SARIF formatter(不写 package.json,避免业务仓引入 lint 工具依赖)
- name: Install dependencies
run: npm install
- name: Install SARIF formatter
run: npm install --no-save --no-package-lock @microsoft/eslint-formatter-sarif@3.1.0
# ESLint 扫描:formatter 输出 SARIF v2.1.0;检出违规不阻断(失败语义三分离)
- name: 运行 ESLint 扫描
run: |
mkdir -p reports
npx eslint src/ \
--format @microsoft/eslint-formatter-sarif \
--output-file reports/eslint.sarif \
--no-error-on-unmatched-pattern || true
- name: Upload SARIF to openLiBing
if: ${{ always() }}
uses: openlibing/upload-sarif-action@v1.0.0
with:
sarif_file: reports/eslint.sarif
source_path: src # 源码根目录,用于补齐代码片段
category: "eslint-scan"
# ===================== C/C++ =====================
clang-tidy-scan:
name: clang-tidy 扫描
runs-on: ["codearts-hosted", "ubuntu-latest", "x64", "slim"]
steps:
- name: Checkout
uses: checkout
with:
ref: ${{ atomgit.event.pull_request.merge_commit_sha || atomgit.event.pull_request.head.sha || atomgit.ref }}
- name: Install clang-tidy
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy
clang-tidy --version
# 预置二进制 clang-tidy-sarif 随本仓 .gitcode/bin/ 提交(见工具文档 §5.1)
- name: Ensure clang-tidy-sarif executable
run: |
chmod +x .gitcode/bin/clang-tidy-sarif
.gitcode/bin/clang-tidy-sarif --version || true
# 仅配置阶段产出 compile_commands.json,不执行编译(节省时间)
- name: Build CMake compile_commands.json
run: |
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Release
test -f build/compile_commands.json || { echo "ERROR: compile_commands.json not generated"; exit 1; }
# 全量扫描 + 转换 SARIF(wrapper 脚本提取 compile_commands.json 全部源文件)
- name: clang-tidy scan and convert to SARIF
run: |
mkdir -p sarif
python3 scripts/run-clang-tidy.py \
--_cdb build/compile_commands.json \
--_clang-tidy-sarif .gitcode/bin/clang-tidy-sarif \
--_sarif-output sarif/clang-tidy.sarif \
|| echo "clang-tidy exited non-zero (issues found), continuing"
test -s sarif/clang-tidy.sarif || { echo "ERROR: SARIF empty"; exit 1; }
- name: Upload SARIF to openLiBing
if: ${{ always() }}
uses: openlibing/upload-sarif-action@v1.0.0
with:
sarif_file: sarif/clang-tidy.sarif
source_path: .
category: "clang-tidy-scan"
# ===================== Rust =====================
cargo-clippy-scan:
name: cargo-clippy 扫描
runs-on: ["codearts-hosted", "ubuntu-latest", "x64", "slim"]
# 工具链版本统一固定,保证 CI 环境可复现(clippy 随工具链版本发布)
env:
RUST_TOOLCHAIN: "1.98.1"
CLIPPY_SARIF: "0.8.0"
steps:
- name: Checkout
uses: checkout
with:
ref: ${{ atomgit.event.pull_request.merge_commit_sha || atomgit.event.pull_request.head.sha || atomgit.ref }}
# 安装 Rust 工具链:RsProxy 国内镜像加速,版本由 env.RUST_TOOLCHAIN 固定,幂等
- name: setup-rust
run: |
export RUSTUP_DIST_SERVER="https://rsproxy.cn"
export RUSTUP_UPDATE_ROOT="https://rsproxy.cn/rustup"
if ! command -v rustup >/dev/null 2>&1 && [ ! -x "$HOME/.cargo/bin/rustup" ]; then
echo "rustup not found, installing..."
curl --proto '=https' --tlsv1.2 -sSf https://rsproxy.cn/rustup-init.sh | \
sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN"
else
echo "rustup already exists, ensure toolchain $RUST_TOOLCHAIN ..."
rustup toolchain install "$RUST_TOOLCHAIN" --no-self-update
rustup default "$RUST_TOOLCHAIN"
fi
. "$HOME/.cargo/env"
rustup --version && cargo --version && rustc --version
echo "$HOME/.cargo/bin" >> "$ATOMGIT_PATH"
- name: install clippy component
run: |
. "$HOME/.cargo/env"
export RUSTUP_DIST_SERVER="https://rsproxy.cn"
export RUSTUP_UPDATE_ROOT="https://rsproxy.cn/rustup"
if rustup component list --installed --toolchain "$RUST_TOOLCHAIN" | grep -q "^clippy"; then
echo "clippy component already installed, skip"
else
rustup component add clippy --toolchain "$RUST_TOOLCHAIN"
fi
- name: install clippy-sarif
run: |
. "$HOME/.cargo/env"
mkdir -p ~/.cargo
cat > ~/.cargo/config.toml <<'EOF'
[source.crates-io]
replace-with = "rsproxy-sparse"
[source.rsproxy-sparse]
registry = "sparse+https://rsproxy.cn/index/"
EOF
if command -v clippy-sarif >/dev/null 2>&1; then
echo "clippy-sarif already installed, skip"
else
cargo install clippy-sarif --version "$CLIPPY_SARIF" --locked
fi
# 全量扫描 + 转换 SARIF:cargo clippy JSON 诊断流 pipe 给 clippy-sarif(只出报告不拦截)
- name: cargo-clippy scan and convert to SARIF
run: |
mkdir -p /tmp/clippy-result
cargo clippy --message-format=json | clippy-sarif > /tmp/clippy-result/clippy-results.sarif
cat /tmp/clippy-result/clippy-results.sarif
- name: Upload SARIF to openLiBing
if: ${{ always() }}
uses: openlibing/upload-sarif-action@v1.0.0
with:
sarif_file: /tmp/clippy-result/clippy-results.sarif
source_path: src # 源码根目录,用于补齐代码片段(workspace 多 crate 建议传仓库根 .)
category: "cargo-clippy-scan"
# ===================== Java =====================
spotbugs-scan:
name: SpotBugs 扫描
runs-on: ["codearts-hosted", "ubuntu-latest", "x64", "slim"]
steps:
- name: Checkout
uses: checkout
- name: setup-jdk
uses: setup-jdk
with:
jdk-version: 21
maven-version: "3.8.9"
# SpotBugs 分析字节码,需先编译产出 target/classes
- name: 编译
run: mvn -B clean package -DskipTests
# SpotBugs 扫描:版本/规则过滤/SARIF 输出等配置在目标仓 pom.xml 声明(单一事实源)
- name: SpotBugs 扫描
run: mvn -B spotbugs:spotbugs
# 上传 SARIF:if: always() 保证扫描失败也上传(只要有 SARIF 文件)
- name: upload sarif to openlibing
if: ${{ always() }}
uses: openlibing/upload-sarif-action@v1.0.0
with:
sarif_file: target/reports/spotbugs.sarif
source_path: src/main/java
category: "business"
📌 工具文档中「场景二 完整 workflow 示例」小节给出的是单工具 job,本文档 4.3.1 是全部 job 合并版。多 job 在同一 workflow 内并行执行;如需为某工具配置独立触发/定时,可拆分为单独 workflow 文件。
category建议按工具固定(如gitleaks-scan),便于平台按扫描范围区分结果。
5. 目录结构
solutions/
├── full-analysis/ <- 本方案:分支全量代码检查(总览 + 工具落地文档)
│ ├── README.md <- 方案总览(背景 / 页面说明 / 工具选型 / 方案择优 / 全量配置样例)
│ ├── images/ <- 页面说明截图
│ └── tools/ <- 本方案工具的使用文档(配置样例、参数说明、demo)
│ ├── bandit/ <- Bandit 代码检查指南(pre-commit + workflow 两种用法)
│ ├── cargo-clippy/ <- cargo-clippy 代码检查指南(pre-commit + workflow 两种用法)
│ ├── clang-tidy/ <- clang-tidy 代码检查指南(pre-commit + workflow 两种用法)
│ ├── codearts-check/ <- CodeArts Check 代码检查指南(华为云云端托管服务,仅 workflow 集成)
│ ├── eslint/ <- ESLint 代码检查指南(pre-commit + workflow 两种用法)
│ ├── gitleaks/ <- Gitleaks 敏感信息扫描指南(pre-commit + workflow 两种用法)
│ ├── gosec/ <- Gosec 代码检查指南(pre-commit + workflow 两种用法)
│ └── spotbugs/ <- SpotBugs 代码检查指南(pre-commit + workflow 两种用法)
├── pre-commit/ <- 独立方案:pre-commit 落地指南(方案一核心载体,不在本方案内)