この記事は後編です
前編では、ホストに Node / Python / Java を一切入れず、Docker だけで SonarQube を立て、
Vue3 + Django REST Framework のプロジェクトを解析してカバレッジを取り込むところまでやりました。
前編の到達点はここです。
| backend (DRF) | frontend (Vue3) | |
|---|---|---|
| Coverage | 47.7% | 52.0% |
| 検出された指摘 | 14 件 | 26 件 |
ところが、この状態で Quality Gate を見ると「Passed」と表示されます。
これだけ指摘が出ているのにです。
後編はその正体から入り、指摘をどう読み、どう運用するかを扱います。
数値・ログ・エンドポイントはすべて実際に動かした結果です。
検証環境: SonarQube Community Build 26.9.0.129388 / Docker 28.2.2 / macOS (x86_64)
この記事の構成
| 章 | 内容 |
|---|---|
| 5 | 検出結果の一覧 — 実際に何が出たか |
| 6 | 出なかった指摘の原因 — 3 パターンの切り分けと Quality Profile のカスタマイズ |
| 7 | Quality Gate が初回素通りする正体 — New Code とは何か |
| 8 | Fail → 修正 → Pass の実演 — 誤検知(False Positive)の扱いも |
| 9 | GitHub Actions 連携 |
| 10 | 静的解析の深さ — どこまで見るのか、脆弱性検出の限界 |
| 11 | Community Build の線引き — 有償版が必要になる境界 |
S106 のような個別ルールの解説は、分量が多いので
**別記事「SonarQube ルール早見表(Vue3 + DRF 編)」**にまとめています。
5. 何が検出されたか
検証アプリには典型的な問題コードを仕込みました。修正前の backend で 14 件です。
| ルール | 種別 | 内容 |
|---|---|---|
secrets:S6687 |
Vulnerability (BLOCKER) |
SECRET_KEY のハードコード |
python:S4507 |
Vulnerability | DEBUG = True |
python:S4502 ×2 |
Vulnerability (CRITICAL) | CSRF 保護の無効化(@csrf_exempt と middleware 未設定) |
python:S4790 |
Vulnerability (CRITICAL) | MD5 でのハッシュ化 |
python:S2245 |
Vulnerability |
random をセキュリティ用途に使用 |
python:S4830 |
Vulnerability (CRITICAL) |
verify=False(TLS 検証の無効化) |
python:S3752 |
Vulnerability | HTTP メソッドの未指定 |
python:S1763 |
Bug |
return 後の到達不能コード |
python:S1862 |
Bug | 同じ条件の elif で到達しない分岐 |
python:S1192 |
Code Smell | 3 回重複した文字列リテラル |
python:S1135 |
Code Smell |
TODO コメント |
python:S1481 |
Code Smell | 未使用のローカル変数 |
python:S3776 |
Code Smell | 認知的複雑度 28(上限 15) |
frontend は 26 件。Vue3 特有のものを抜粋します。
| ルール | 種別 | 内容 |
|---|---|---|
typescript:S1656 |
Bug | 自己代入(title = title) |
typescript:S1862 |
Bug | 同じ条件の else if
|
Web:InputWithoutLabelCheck |
Bug |
<input> に label が無い(アクセシビリティ) |
typescript:S2245 |
Vulnerability | Math.random() |
typescript:S4144 ×2 |
Code Smell | 実装が同一の関数(コピペ検出) |
typescript:S1854 |
Code Smell | 使われない代入 |
typescript:S2486 |
Code Smell | 空の catch
|
typescript:S2699 |
Code Smell (BLOCKER) | アサーションが無いテスト |
typescript:S3776 |
Code Smell | 認知的複雑度 22 |
typescript:S7781 |
Code Smell |
replace() より replaceAll() を使う |
S2699(アサーション無しテスト)が BLOCKER で出るのは実用的だと感じました。
「通っているつもりのテスト」を検出できます。
Security Hotspot は 0 件だった
意外だったのですが、security_hotspots = 0 で、/api/hotspots/search も空でした。
従来 Security Hotspot に分類されていたルール(MD5、擬似乱数、TLS 検証無効化など。
メッセージが "Make sure ... is safe here" になっているもの)が、
26.9 では Vulnerability として集計されています。
先行記事にある「Overview に Security Hotspots が出る」という説明とは
挙動が変わっているので、バージョンによって読み替えが必要です。
6. つまずき④ 仕込んだのに検出されない指摘がある
ここが一番の発見でした。仕込んだのに出ないものが複数ありました。
原因は 3 種類に分かれます。/api/rules/show と /api/rules/search で切り分けました。
| 仕込んだもの | 結果 | 原因 |
|---|---|---|
v-html での XSS |
検出されない | ルール自体が存在しない |
ALLOWED_HOSTS = ["*"] |
検出されない | ルール自体が存在しない |
eval() での動的実行 |
検出されない | Python 用のルールが存在しない |
console.log の残留 |
検出されない |
typescript:S106 はあるが Sonar way で無効
|
== による比較 |
検出されない |
typescript:S1440 が無効 |
any の使用 |
検出されない |
typescript:S4204 が無効 |
未使用の import(Python) |
検出されない |
python:S1128 が無効 |
| API トークンのハードコード | 検出されない |
typescript:S2068 は有効だが変数名が合致せず |
| SQL インジェクション等 | 検出されない | taint analysis は Developer Edition 以上 |
確認方法はこうです。
# ルールが存在するか・有効かを調べる
curl -s -u "admin:$PASS" "$SONAR_URL/api/rules/show?key=typescript:S106&actives=true"
# → rule は返るが actives が空 = 存在するが無効
# ルールキーが分からないときはキーワードで検索する
curl -s -u "admin:$PASS" "$SONAR_URL/api/rules/search?q=console&languages=js,ts"
ここから導ける運用方針
SonarQube だけで Vue3 / DRF の品質を担保しようとしないこと。
-
v-htmlの XSS は SonarQube では拾えないので、ESLint のvue/no-v-htmlが必要 -
console.log、==、anyは ESLint / TypeScript の設定で止めるのが素直 - Python の未使用 import は ruff / flake8 の担当
SonarQube の強みは、認知的複雑度・重複・カバレッジ・セキュリティ設定の指摘を
ダッシュボードで時系列に追えることでした。リンターの置き換えではなく、
リンターが見ないレイヤを埋めるツールと考えるのが実態に合っています。
無効になっているルールは有効化できる
パターン B(存在するが無効)は、Quality Profile をカスタマイズすれば検出できます。
実際にやってみました。
-
Quality Profiles→ TypeScript のSonar wayをCopy
(Sonar wayはBuilt-inなので直接編集できません。コピーが必須)

-
再解析(Quality Gate と同じで、プロファイルを変えても再解析しないと反映されません)
結果、指摘が 26 件 → 30 件に増えました。
| ルール | 増えた件数 | 検出された場所 |
|---|---|---|
typescript:S4204(any の使用) |
3 件 |
composables/useTodos.ts、api/client.ts
|
typescript:S106(console.log の残留) |
1 件 | composables/useTodos.ts |
「デフォルトが緩いなら締められる」 ということです。ただし ESLint で止めれば済む内容も
多いので、どちらの層で止めるかをチームで決めておくのが現実的です。
有効化するときの注意点 2 つ
① 同じルールが言語ごとに別キーで存在する
[無効] javascript:S106 Standard outputs should not be used...
[無効] typescript:S106 Standard outputs should not be used...
プロファイルは言語単位です。.js と .ts が混在するプロジェクトでは、
両方の言語のプロファイルで有効にしないと片方だけ検出されません。
② 同じ問題でも言語によって検出できるルールが違う
「空の例外ハンドラ」を両方に仕込んだところ、結果が非対称でした。
| 仕込んだコード | 結果 | |
|---|---|---|
| frontend | catch (error) { } |
✅ typescript:S2486 で検出 |
| backend | except Exception: pass |
❌ 該当ルールが Sonar way に無い |
「Python で出たから TypeScript でも出る」とは限りません。 言語ごとにルールセットの
成熟度が違うので、両方のプロファイルを個別に確認する必要があります。
7. つまずき⑤ 初回スキャンで Quality Gate が必ず素通りする
初回スキャン直後、あれだけ指摘が出ているのに Quality Gate は OK でした。
理由は条件定義を見れば分かります。デフォルトの Sonar way はこうなっています。
new_violations GT 0
new_coverage LT 80
new_duplicated_lines_density GT 3
new_security_hotspots_reviewed LT 100
4 つ全部が new_*(New Code 側)です。
初回解析には比較対象の New Code が存在しないため、判定条件が 0 件になり、
そのまま合格になります。実際 API で見ると conditions が空でした。
これは設計思想で、Clean as You Code(既存の負債は一旦置き、
これから書くコードをきれいに保つ)という考え方です。新規プロジェクトには合いますが、
既存プロジェクトに後から入れて「今の品質」を可視化したい場合は条件を足す必要があります。
何回スキャンしても New Code が空のままだった
ここで当然の疑問が出ます。「2 回目・3 回目のスキャンなら、前回との差分が New Code に
なるのでは?」 — ところが、何回スキャンしても空のままでした。
原因は sonar-project.properties のこの 1 行です。
sonar.projectVersion=0.1.0
New Code の既定の定義は **PREVIOUS_VERSION(前回バージョン以降)**です。
API で確認すると理由がはっきりします。
New Code の定義:
{"projectKey":"qube-test-backend","type":"PREVIOUS_VERSION","inherited":true}
解析履歴:
11:22:33 projectVersion = "0.1.0"
11:39:04 projectVersion = "0.1.0" ← 2 回スキャンしたが同じ
VERSION イベントは "0.1.0" の 1 つだけ
区切りはスキャン回数ではなく「バージョンが変わったかどうか」で決まります。
バージョンを固定していたため「前回のバージョン」が存在せず、基準点が定まりませんでした。
New Code が機能する条件は 2 つある
| やること | New Code はどうなるか |
|---|---|
| バージョンを上げるだけ | 基準点はできるが、変更行が無いので 0 件 |
| コードを変えるだけ | 基準点が無いので 0 件のまま(今回の状態) |
| 両方 | 変更分が New Code に現れる |
どちらか一方では動きません。
実プロジェクトでは projectVersion を固定しない
検証用に固定で書いたのが原因なので、実務では CI で注入します。
# package.json から取る
-Dsonar.projectVersion=$(node -p "require('./package.json').version")
# git tag から取る
-Dsonar.projectVersion=$(git describe --tags --abbrev=0)
リリースごとに区切りができ、コードは日々変わるので New Code は自動的に機能します。
バージョン運用をしたくない場合は定義を変える
Administration → New Code で 4 種類から選べます。
| 定義 | 基準 | 向いている場面 |
|---|---|---|
| Previous version(既定) | 前回 projectVersion が変わった解析以降 |
リリース単位で区切る |
| Number of days | 過去 N 日間に変更された行 | リリースを切らない継続開発。一番扱いやすい |
| Specific analysis | 指定した解析以降 | 既存プロジェクトへの導入直後 |
| Reference branch | 指定ブランチとの差分 | Developer Edition 以上 |
既存プロジェクトに後から入れるなら Specific analysis で導入日を基準にするのが
実用的です。「今日以降に書いたコードだけを見る」状態が作れます。
git 管理下でないと精度が落ちる
もう 1 つ要因があります。この検証環境は git リポジトリではなかったため、
スキャンのたびにこの警告が出ていました。
WARN SCM provider autodetection failed. Please use "sonar.scm.provider" to define
SCM of your project, or disable the SCM Sensor in the project settings.
SonarQube は git の blame から行ごとの変更日を取得して New Code を判定します。
SCM が無いと行レベルの精度が落ちるため、実プロジェクトでは必ず git 管理下で
スキャンしてください(CI で fetch-depth: 0 が必要なのも同じ理由です)。
「既存の負債は据え置き、今回入れた指摘だけで落とす」 — これが SonarQube が
本来想定している運用の姿です。導入時にはご自身の環境で確認してください。
Overall Code を見る条件を追加する
curl -s -u "admin:$PASS" -X POST "$SONAR_URL/api/qualitygates/create" \
--data-urlencode "name=qube-test strict"
# rating 系は 1=A, 2=B, ... 5=E なので「GT 1」で A 以外を落とす
for cond in "coverage:LT:70" "duplicated_lines_density:GT:3" \
"reliability_rating:GT:1" "security_rating:GT:1"; do
IFS=: read -r metric op err <<< "$cond"
curl -s -u "admin:$PASS" -X POST "$SONAR_URL/api/qualitygates/create_condition" \
--data-urlencode "gateName=qube-test strict" \
--data-urlencode "metric=$metric" --data-urlencode "op=$op" \
--data-urlencode "error=$err"
done
curl -s -u "admin:$PASS" -X POST "$SONAR_URL/api/qualitygates/select" \
--data-urlencode "gateName=qube-test strict" \
--data-urlencode "projectKey=qube-test-backend"
なお、新規作成した Quality Gate にはデフォルトの new_* 条件が最初から入っていました。
追加した 4 条件と合わせて 8 条件になります。
※画面上での設定の仕方は、先述した解決策を参照してください。
重要:ゲートを差し替えても再解析するまで判定は変わらない
差し替えた直後に判定を見たら OK のままでした。
qube-test-backend 適用ゲート: qube-test strict
--- 判定: OK --- ← 再解析していないので古い判定のまま
再スキャンしたら期待通り落ちました。
--- 判定: ERROR ---
[NG!] coverage actual=52.0 (閾値 LT 70)
[NG!] duplicated_lines actual=51 (閾値 GT 3)
[OK ] new_violations actual=0 (閾値 GT 0)← New Code が無いので 0 件扱い
[NG!] software_quality_reliability_rating actual=3 (閾値 GT 1)
[NG!] software_quality_security_rating actual=3 (閾値 GT 1)
Quality Gate の判定は解析時に評価されるので、CI で運用する場合は
「ゲートを変えたら次の解析から効く」と理解しておく必要があります。
8. Fail → 修正 → Pass をやってみる
backend の指摘を実際に直しました。主な修正内容です。
# 修正前
SECRET_KEY = "django-insecure-3k9v2m8x7q1w..." # secrets:S6687
DEBUG = True # python:S4507
ALLOWED_HOSTS = ["*"]
# 修正後
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY") or get_random_secret_key()
DEBUG = os.environ.get("DJANGO_DEBUG", "false").lower() == "true"
ALLOWED_HOSTS = [h.strip() for h in
os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost,127.0.0.1").split(",")]
# 修正前: python:S4790 / S2245 / S4830
return hashlib.md5(raw_password.encode()).hexdigest()
suffix = "".join(random.choice(alphabet) for _ in range(16))
requests.post(url, verify=False, timeout=5)
# 修正後
return make_password(raw_password) # Django 標準(PBKDF2)
return f"{todo_id}-{secrets.token_urlsafe(12)}" # secrets モジュール
requests.post(url, timeout=5) # verify は既定(有効)のまま
認知的複雑度 28 の関数は、役割ごとに 3 つの関数へ分割しました
(_count_status / _count_priority / _collect_warnings)。
コピペされていた 3 つの CSV エクスポート関数は 1 つに統合しました。
そしてテストを追加してカバレッジを 96%(SonarQube 表示 78.9%)まで上げました。

coverage.py の 96% と SonarQube の 78.9% がずれるのは、集計対象が違うためです。
.coveragercのomitで除外したファイルも SonarQube 側では
「カバレッジ 0% のファイル」として計上されます。
修正の結果、新しい指摘が出た
再スキャンしたら、直したはずが今度は別の 4 件が出ました。
| ルール | 場所 | 内容 |
|---|---|---|
python:S5863 ×2 |
tests/test_services.py |
同じ式を左右に置いた assert |
python:S5443 |
todos/services.py |
/tmp(誰でも書けるディレクトリ)の使用 |
python:S125 |
config/settings.py |
「コメントアウトされたコード」 |
S5863 は自分のテストの書き方の問題でした。
# 指摘される
assert hash_password("same") != hash_password("same")
# 一度変数に受ける
first = hash_password("same")
second = hash_password("same")
assert first != second
S5443 は /tmp/todo-archive.log を既定値にしていたのが原因で、アプリ配下に変更。
最後の 1 件は誤検知だった
python:S125 が指した行はこれです。
# 環境変数から読み、無ければ実行ごとに使い捨ての鍵を生成する。
日本語のコメントを「コメントアウトされたコード」と誤検知していました。
日本語のコメントを書く日本語圏のプロジェクトでは、これは避けられません。
コードを歪めて回避するのではなく、理由を添えて False Positive として解決するのが
正しい運用です。画面なら指摘を開いて False Positive を選ぶだけ。API ならこうです。
# 理由をコメントとして残す(後から判断を追えるように)
curl -s -u "admin:$PASS" -X POST "$SONAR_URL/api/issues/add_comment" \
--data-urlencode "issue=$ISSUE_KEY" \
--data-urlencode "text=日本語コメントをコードと誤認した誤検知のため"
curl -s -u "admin:$PASS" -X POST "$SONAR_URL/api/issues/do_transition" \
--data-urlencode "issue=$ISSUE_KEY" \
--data-urlencode "transition=falsepositive"
Quality Gate の差し替えと違い、False Positive のマークは即座に反映されました。
この操作だけで判定が ERROR → OK に変わりました。
qube-test-backend 適用ゲート: qube-test strict
--- 判定: OK ---
余談:git 管理下でスキャンする
検証中ずっとこの警告が出ていました。
WARN SCM provider autodetection failed. Please use "sonar.scm.provider" to define
SCM of your project, or disable the SCM Sensor in the project settings.
解析対象を git リポジトリにしていなかったためです。解析自体は成功しますが、
SonarQube は git の blame 情報から「その行がいつ書かれたか」を判断して
New Code を決めます。SCM 情報が無いと New Code の判定が正しく働かないので、
実プロジェクトでは必ず git 管理下でスキャンしてください
(CI では fetch-depth: 0 が必要なのも同じ理由です)。
余談:指摘の件数が合わないときは resolved=false
修正後に API で指摘を数えたら 18 件返ってきて「直ってない?」と焦りました。
/api/issues/search は resolved を指定しないと修正済み(FIXED / CLOSED)も返します。
# 未解決のみ
curl -s -u "admin:$PASS" "$SONAR_URL/api/issues/search?components=$KEY&resolved=false"
未解決だけに絞ったら 4 件で、ダッシュボードと一致しました。
(未検証)9. GitHub Actions 連携
SONAR_TOKEN と SONAR_HOST_URL を Secrets に入れて使います(先行記事と同じ)。
projectBaseDir を変えて 2 ジョブに分けます。
name: SonarQube
# Community Build はブランチ解析・PR デコレーションに非対応。
# PR ごとに解析を投げても結果が分離されず、同じプロジェクトを上書きしてしまう。
# そのため既定では main への push のみで動かす。
on:
push:
branches: [main]
workflow_dispatch:
jobs:
backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # SCM 情報を使うので浅いクローンにしない
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- run: pip install -r backend/requirements.txt
# カバレッジ生成は「スキャンより前」。逆にすると Coverage が 0% になる
- name: テストとカバレッジ生成
working-directory: backend
run: |
coverage run -m pytest
coverage xml
- uses: SonarSource/sonarqube-scan-action@v8
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
projectBaseDir: backend
- uses: sonarsource/sonarqube-quality-gate-action@master
timeout-minutes: 10
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
pollingTimeoutSec: 600
frontend 側は setup-node + npm ci + npm run test:coverage に置き換えるだけです。
注意点を整理します。
-
sonarqube-scan-actionは v8 が最新(先行記事の頃より進んでいます) - Quality Gate で CI を落とすには
sonarqube-quality-gate-actionを併用。
scan-actionと組み合わせる場合scanMetadataReportFileの指定は不要 -
セルフホストの SonarQube は GitHub Actions ランナーから到達できる必要があります。
社内 LAN に置くなら self-hosted runner が必要です - Community Build で PR 単位の結果を見たいなら Developer Edition 以上が必要
10. SonarQube は「どこまで」見ているのか
「静的解析」と一括りにされますが、実際には深さに段階があります。ここを理解しておくと、
何を SonarQube に任せられて、何は別のツールが必要かの判断ができます。
解析の深さは 4 段階
| 深さ | 見ているもの | 今回の実例 | Community Build |
|---|---|---|---|
| ① 構文 | コードの形 |
TODO コメント、except: pass の形 |
✅ |
| ② 型 | 型チェッカーを動かして型を解決 | 下記参照 | ✅ |
| ③ 関数内のフロー | 制御フロー・データフロー |
S1763 到達不能コード、S1854 代入したが読まれない |
✅ |
| ④ 関数/ファイルを越えた追跡 | taint analysis | (検出されなかった) | ❌ Developer 以上 |
②については、スキャンログが証拠になります。
INFO Found 1 tsconfig.json file(s): [/usr/src/frontend/tsconfig.json]
INFO Creating TypeScript(6.0.3) program with configuration file .../tsconfig.json
INFO Analyzing 16 file(s) from tsconfig ... (76 total files in program)
tsconfig.json を読んで TypeScript の型チェッカーを動かしています(76 total files は
node_modules の型定義を含む数)。
そのおかげで面白い挙動がありました。== をわざと書いたのに指摘されなかったのです。
if (todo.title == '') { // 指摘なし
型情報から todo.title が string と分かるため、== でも === と同じ結果になると
判断して黙ったわけです。単純な構文マッチではこうなりません。
脆弱性は 3 種類に分けて考える
「SonarQube は脆弱性を見るのか」への答えは 「種類による」 です。
| 型 | 例 | Community Build | 補う手段 |
|---|---|---|---|
| 危険な API / 設定の誤用 | MD5、DEBUG=True、verify=False、秘密鍵のハードコード |
✅ 今回 8 件検出 | — |
| インジェクション系 | SQLi、XSS、コマンド注入、パストラバーサル | ❌ | Semgrep、bandit、eslint-plugin-security |
| 依存ライブラリの既知脆弱性(CVE) |
requirements.txt の古いパッケージ |
❌ |
Dependabot、pip-audit、npm audit、Trivy |
1 つ目が検出できるのは「1 箇所を見れば判断できる」からです。hashlib.md5( と書いてあれば、
それだけで危険と分かります。
2 つ目は入力から出力までの経路を追う必要があるため、taint analysis が要ります。
3 つ目は特に見落としやすいので注意してください。スキャンログにこう出ます。
INFO ------------- Gather SCA dependencies on project
INFO Dependency analysis skipped ← スキップされている
SCA(Software Composition Analysis)は Advanced Security アドオンで Enterprise Edition
以上が必要です。Community Build では依存ライブラリの CVE を一切検出しません。
11. Community Build でどこまでできるか
実際に触って分かった線引きです。
できたこと
- Python / TypeScript / Vue(SFC) / CSS / HTML の解析
- カバレッジの取り込み(Cobertura XML / LCOV)
- 重複コードの検出(コピペ関数を
S4144と Duplications 10.9% で検出) - 認知的複雑度の定量化(28 → 上限 15 という形で出る)
- Quality Gate のカスタマイズと CI での判定
- Web API による初期化・結果取得・誤検知処理の自動化
できなかったこと(Developer Edition 以上が必要)
- ブランチ解析・PR デコレーション
- モノレポとしての一元管理(2 プロジェクトに分けて回避)
- taint analysis(SQL インジェクション、パストラバーサル等のデータフロー追跡)
できなかったこと(Enterprise Edition + Advanced Security アドオンが必要)
-
SCA(依存ライブラリの既知脆弱性・ライセンス違反の検出)
… ログにDependency analysis skippedと出て、requirements.txt/
package.jsonは一切チェックされない
社内展開では、まず Community Build で「複雑度・重複・カバレッジの可視化」を回し、
PR 連携やインジェクション検出が必要になった段階で有償版を検討する、
という順序が現実的だと思います。
なお日本語化は、クレスコさんの SonarQube Japanese Pack を
extensions/plugins に置いて再起動する形です(今回は英語 UI のまま検証しました。
プラグインはバージョン対応の確認が必要です)。
まとめ
後編で押さえた要点です。
-
初回スキャンで Quality Gate は素通りする。
Sonar wayの条件は 4 つ全部が
New Code 側。既存コードを評価したいなら Overall Code の条件を足して再解析する -
sonar.projectVersionを固定すると New Code は永久に空のまま。
区切りはスキャン回数ではなくバージョンが変わったかどうかで決まる。
CI で注入するか、New Code の定義をNumber of days/
Specific analysisに変える。git 管理下でないと行レベルの精度も落ちる -
反映のタイミングが操作によって違う
操作 再解析が必要か Quality Gate の条件を変更 必要 Quality Profile のルールを変更 必要 指摘を False Positive にする 不要(即時) -
v-htmlやconsole.logは検出されない。 原因は「ルールが存在しない」と
「存在するが無効」の 2 パターンで、後者は Quality Profile をコピーして有効化できる -
ESLint / ruff と併用する前提で設計する。 SonarQube の強みは、リンターが見ない
認知的複雑度・重複・カバレッジの定量化と、推移の可視化 -
日本語コメントは
S125で誤検知される。コードを歪めて回避せず、
理由を添えて False Positive で解決する -
脆弱性は「設定・API の誤用」までしか見ない。 インジェクション系は
Developer Edition 以上、依存ライブラリの CVE は Enterprise + Advanced Security が必要
社内に入れるときの現実的な順序
前後編を通して検証した結果、この順序を勧めます。
-
まず Community Build で「可視化」だけ始める — Quality Gate は既定の
Sonar way
(New Code のみ)のままにして、既存の負債では落とさない -
新規に書くコードだけきれいに保つ(Clean as You Code)。これが SonarQube の
設計思想に沿った使い方で、チームの抵抗も少ない -
既存コードの現状を把握したいときだけ Overall Code 条件を足した別ゲートを作り、
レポート目的で使う -
足りない部分は他ツールで埋める —
v-htmlは ESLint、依存の CVE は DependabotやTrivy - PR 連携やインジェクション検出が必要になった段階で有償版を検討する
検証環境一式
Docker Compose / Makefile / 自動化スクリプト / 指摘を仕込んだアプリは、
そのまま動く形でまとめてあります。make all だけで起動から解析結果の表示まで通ります。
cp .env.example .env
make all









