GitHubでSonarCloudを利用する

2022-08-21

背景

publicなリポジトリならSonarCloudによる静的解析を無料で利用できるので試してみた。

環境

  • GitHub
  • TypeScript(JavaScript)
  • Jest
  • Visual Studio Code

Repository

Sonar

コードの静的解析ツール。20以上の言語に対応しており、保守性や脆弱性に影響を及ぼす可能性のあるコードを報告してくれる。また、次の3つのプロダクトを提供する。

Product 説明
SonarLint ローカル開発でのリアルタイムの静的解析
SonarQube 自前でサーバーをホスティングして利用する静的解析ツール
SonarCloud GitHubやBitBucketと連携して静的解析できるSaaS

SonarCloud

オープンソースのプロジェクトなら無料で利用できる。(設定時にFree Planを選択できる)。Pull Request作成時にCIと連携することやメインブランチなどの自動解析が可能。

SonarCloudが検出するもの

IssuesSecurity Hotspots に分類される。IssuesはさらにCode Smells、Bugs、Vulnerabilitiesに分類される。

Code Smells

保守性(maintainability)に影響を及ぼす可能性のあるコードの特徴を検出する。

例: 上位のスコープで定義された変数を下位のスコープで再定義する

const foo = 'value'
arr.map(foo => {
  // ...
})

Bugs

信頼性(reliability)に影響を及ぼす可能性のあるコードを検出する。

例: 引数の上書き

const func => (foo, bar) => {
  // bug!
  foo = 'overwrite'
}

Vulnerabilities

セキュリティ(security)に影響を及ぼす可能性のある脆弱性を検出する。

例: 脆弱性の報告されている暗号化方式を利用している

Security Hotspots

脆弱性やバグを特定するときよりも基準は厳格でないが、問題を引き起こす可能性のあるコードを警告する(security review)。

やったこと

  1. SonarCloudのアカウント作成
  2. 解析対象の連携(今回はGitHub)
  3. SonarCloudへリポジトリのインポート
    • Organizationか個人アカウントを一括でインポートできる
    • 今回は設定するリポジトリのみを指定
  4. 設定ファイルの追加
  5. [オプショナル]sonarLintの導入

セットアップ

GitHubを選択。

setup with GitHub on SonarCloud

Analyze new projectを選択。

init project on SonarCloud

始めての利用なのでOrganizationの作成と対象のリポジトリを選択する。

init organization on SonarCloud

Organazationの設定

set organization name on SonarCloud

Publicなリポジトリなので無料プランを選択できる。

select plan on SonarCloud

作成したプロジェクトを選択してセットアップ。

setup analytics on SonarCloud

Quality Gate

Quality Gateは現在のメインブランチのコードがリリースに値するかの指標を提供する。解析にはコード全体に適用される条件と新しいコードに適用される条件を区別し、新しいコードの解析結果から測定される。

quality gate on SonarCloud

New Code

New Codeを定義することで、SonarCloudが新しく追加されたメインブランチへの変更を分析できる。

New Codeの定義はAdministrator → New Codeで次の3つから選択する。

select new code definition on Administrator

Previous version

前回のバージョンからの変更をNew Codeとする。Maven・Gradle以外のバージョンは自動でバージョン変更を読み取ることはできず、 sonar.projectVersion を明示的に指定する。

Number of days

指定日数までの変更をNew Codeとする。

Specific date

指定した年月日以降の変更をNew Codeとする。

Quarity Gateの有効化

Administration → Quality Gatesから設定する。デフォルトでは定義済みのSonary Wayが適用されている。

New Codeの定義後にSonarCloudの解析を再度実施するとOverviewの「Main Branch Status」が更新される。

CI-based Analysis

CI-based AnalysisはメインブランチへのマージやPull Requestごとに変更のあったコードのみを対象とした静的解析。

SonarCloud report on Pull Request

GitHubのリポジトリをセットアップ後はAutomatic Analysisが自動で有効となる。Automatic Analysisは自動でPull Request、メインブランチの静的解析を行うが、CI-based Analysisと併用できないため無効にする(変更には管理者権限が必要)。

turn off automatic analytics method

GitHub Actionsの手順に従い、設定する。

1. GitHubへトークンの登録

SonarCloudから指定されたトークンをGitHubの Settings → Secretsで SONAR_TOKEN を登録する。

set SonarCloud token to GitHub

2. GitHub Actionsの設定

リポジトリにGitHub Actionsの設定ファイル .github/workflows/build.yml を追加する。

name: Build
on:
  push:
    branches:
      - main # PRマージ先のブランチを設定する
  pull_request:
    types: [opened, synchronize, reopened]
jobs:
  sonarcloud:
    name: SonarCloud
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
      - name: SonarCloud Scan
        uses: SonarSource/sonarcloud-github-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

リポジトリにSonarCloudの設定ファイル sonar-project.properties を追加する。

sonar.projectKey=kkenya_sonarcloud-practice
sonar.organization=kkenya

sonar.sources=src
sonar.tests=__tests__
sonar.typescript.tsconfigPath=tsconfig.json
key value
sonar.sources コード全体のパスを指定
sonar.tests テストコードのパスを指定
sonar.typescript.tsconfigPath tsconfig.jsonのパスを指定

言語ごとの設定項目はAdministrator → General Settingsから確認できる。

language in geneal setting

テストカバレッジの計測

カバレッジの計測はAutomatic Analysisでサポートされていない(javascript-typescript-test-coverage)。別途CI-based Analysisを設定する。

カバレッジ計測の条件はCIの実行時にレポートファイルをLCOV形式で出力し、SonarCloudのスキャナーが取得できること。

SonarCloudの解析前に、Jestでカバレッジレポートを生成するステップをGitHub Actionsに追加する。

.github/workflows/build.yml

       - uses: actions/checkout@v2
         with:
           fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+      - name: Install dependencies
+        run: npm install --include=dev
+      - name: Test and coverage
+        run: npm test
       - name: SonarCloud Scan
         uses: SonarSource/sonarcloud-github-action@master
         env:

SonarCloudにカバレッジリポートのパスを指定する。Jestは ./coverage/lcov.info に計測結果を出力する。

sonar-project.properties

sonar.javascript.lcov.reportPaths=./coverage/lcov.info

Badges

SonarCloudのInformationからREADMEで表示するためのバッジを取得できる。バッジのメトリクスにはQuality Gateのステータス、VulnerabilitiesやCoverageなどから選択する。

get sonar cloud badge

Quality Gate Status

SonarLintの導入

開発時にロー買うのコードに対してSonarCloudの解析を実施できる。

複数のエディタに拡張機能が提供されており、今回はVisual Studio Codeの拡張機能を利用した。

プロジェクト設定の共有

SonarCloudで生成したトークンを拡張機能に設定することで、プロジェクトの設定をローカルの静的解析に適用できる。

  1. SonarCloudアカウント設定のsecurityからトークンを生成

generate SonarCloud token

  1. SCodeにトークンを設定

set SonarCloud token on VSCode

Security Hotspotの修正について

httpのURLを許可したい場合など意図的にSecurity Hotspotの報告を修正しない場合はステータスを変更する(参考: Security Hotspot Workflow

スタータスの変更には Administer Security Hotspots の権限が必要になる。権限がないユーザーにはタブ自体が表示されない。

Security hotspots have a dedicated lifecycle. To make status changes, the user needs the Administer Security Hotspots permission. This permission is enabled by default. Users with the Browse permission can comment on or change the user assigned to a security hotspot.

実装時のメモ

jestの導入とテストカバレッジ

TypeScirptでJestを実行するためts-jestを利用する。

npm install --save-dev jest ts-jest @types/jest

@types/jest のバージョンはjestに合わせる。 jest のバージョンが 28.1.0 なら @types/jest28.1.x

設定ファイルの対話的な生成(ts-jestのセットアップスクリプト( npx ts-jest config:init )はjsで生成されるので利用しない)。

npx jest --init

ts-jest でTypeScriptの設定ファイルを利用する場合は ts-node のインストールが必要。

npm install --save-dev ts-node

jest.config.ts にpresetを指定

  preset: "ts-jest",

カバレッジの計測には coverage オプションを指定する。

package.json

"test": "jest --coverage"

カバレッジの集計対象からトランスパイルしたコードを除外する

jest.config.ts

  coveragePathIgnorePatterns: ["/node_modules/", "dist"],

ghコマンドでリポジトリを作成する

create のオプションに --source を指定することでローカルのディレクト名とコミット履歴で作成できる。

gh repo create --public --source=.

参考


Web系ソフトウェアエンジニアの備忘録

Contact: 3982ne@gmail.com