SCANOSS GitHub Actions モノレポ対応:変更コンポーネントだけスキャンする構成

前回の記事ではSCANOSS GitHub Actionsを使った基本的なコードスキャン自動化の手順を紹介しました。基本スキャンやポリシーチェック、サブディレクトリスキャンまで確認できたところで、次に気になるのはモノレポ構成への対応です。

scanPathパラメータは単一の相対パスしか受け付けないため、複数のサブディレクトリを個別にスキャンするにはワークフロー側で工夫が必要です。本記事では、SCANOSS公式のMONOREPO_SETUP.mdで推奨されているreusable workflow(workflow_call)パターンを使い、PRで変更されたコンポーネントだけを自動スキャンする構成を実際に構築・検証します。

この記事でわかること:

  • モノレポでscanPathが抱える制約と解決策
  • reusable workflow(workflow_call)による共通スキャンワークフローの作り方
  • パスフィルターとの連携で、変更コンポーネントだけスキャンする構成
  • 構築時のハマりポイント(permissionsの配置)と解決策

前提条件

  • 前回の記事の内容を理解していること(基本スキャン、scanPathの動作)
  • GitHubリポジトリにActions実行権限があること
  • リポジトリのSettings > SecretsにSCANOSS_KEYを登録済みであること
  • scanoss/gha-code-scan@v1.5.0を使用

検証に使用したリポジトリ構成

本記事の検証には、application/tools/src/配下に複数のPythonパッケージを持つモノレポ構成のリポジトリを使用しました。

application/tools/src/
├── blog_scraper/          # ブログスクレイピングツール(Pythonファイル9個)
├── svg_to_png/            # SVG→PNG変換ツール(Pythonファイル6個)
├── html_to_png/           # HTMLスクリーンショットツール
├── cleanup_articles/      # 記事クリーンアップツール
├── thumbnail_generator/   # サムネイル生成ツール
├── pv_analyzer/           # PV分析ツール
└── notion_sync/           # Notion同期ツール

このうちblog_scrapersvg_to_pngの2ディレクトリをスキャン対象として検証します。

モノレポでのスキャン課題

前回の記事で紹介したscanPathパラメータを使えば、スキャン対象をサブディレクトリに限定できます。しかし、scanPath単一の相対パスしか受け付けません。複数パスのカンマ区切りやワイルドカードには対応していません。

# これはできる
scanPath: application/tools/src/blog_scraper

# これはできない
scanPath: application/tools/src/blog_scraper, application/tools/src/svg_to_png

モノレポで複数パッケージを個別にスキャンするには、ワークフロー側で対応が必要です。SCANOSS公式のMONOREPO_SETUP.mdでは、GitHub Actionsのreusable workflowworkflow_call)を使ったパターンが推奨されています。

ワークフローの全体構成

作成するファイルは以下の3つです。スキャン対象のコンポーネントが増えるたびにトリガーワークフローを1つ追加します。

.github/workflows/
├── scanoss-monorepo-base.yml           # ベースワークフロー(共通、1つだけ)
├── scanoss-monorepo-blog-scraper.yml   # blog_scraper 用トリガー
└── scanoss-monorepo-svg-to-png.yml     # svg_to_png 用トリガー
ファイル役割
scanoss-monorepo-base.ymlworkflow_callで呼び出される共通スキャン処理。scan_pathを入力として受け取る
scanoss-monorepo-blog-scraper.ymlblog_scraperディレクトリの変更時にベースワークフローを呼び出す
scanoss-monorepo-svg-to-png.ymlsvg_to_pngディレクトリの変更時にベースワークフローを呼び出す

ベースワークフローの作成

workflow_callで呼び出される共通のスキャンワークフローです。スキャン対象のパスをinputs.scan_pathとして受け取ります。

# .github/workflows/scanoss-monorepo-base.yml
name: SCANOSS Monorepo Base Scan

on:
  workflow_call:
    inputs:
      scan_path:
        description: 'Directory to scan'
        required: true
        type: string

jobs:
  scanoss-scan:
    name: SCANOSS Scan (${{ inputs.scan_path }})
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
      checks: write
      actions: read
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Run SCANOSS Code Scan
        id: scanoss-scan
        uses: scanoss/gha-code-scan@v1.5.0
        with:
          scanPath: ${{ inputs.scan_path }}
          api.key: ${{ secrets.SCANOSS_KEY }}

permissionsジョブレベルに配置している点が重要です。トップレベルに置くとstartup_failureで失敗します。詳細は後述の「ハマりポイント」で説明します。

コンポーネント別トリガーワークフロー

各コンポーネントにつき1つのワークフローファイルを作成し、ベースワークフローを呼び出します。

# .github/workflows/scanoss-monorepo-blog-scraper.yml
name: SCANOSS Scan - blog_scraper

on:
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write
  checks: write
  actions: read

jobs:
  scan:
    uses: ./.github/workflows/scanoss-monorepo-base.yml
    with:
      scan_path: application/tools/src/blog_scraper
    secrets: inherit
# .github/workflows/scanoss-monorepo-svg-to-png.yml
name: SCANOSS Scan - svg_to_png

on:
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write
  checks: write
  actions: read

jobs:
  scan:
    uses: ./.github/workflows/scanoss-monorepo-base.yml
    with:
      scan_path: application/tools/src/svg_to_png
    secrets: inherit

secrets: inheritでリポジトリのSecretsを呼び出し先に渡します。これにより、ベースワークフロー側で${{ secrets.SCANOSS_KEY }}が使えます。

まずはこのworkflow_dispatch(手動実行)の構成で動作確認した後、次のセクションでパスフィルターを追加します。

パスフィルターとの連携

この構成の最大の利点は、パスフィルターon.pull_request.paths)との組み合わせです。トリガーワークフローにpathsを追加するだけで、PRで変更されたコンポーネントだけスキャンを発火させることができます。

# .github/workflows/scanoss-monorepo-blog-scraper.yml
name: SCANOSS Scan - blog_scraper

on:
  pull_request:
    paths:
      - 'application/tools/src/blog_scraper/**'
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write
  checks: write
  actions: read

jobs:
  scan:
    uses: ./.github/workflows/scanoss-monorepo-base.yml
    with:
      scan_path: application/tools/src/blog_scraper
    secrets: inherit

変更点はon:セクションにpull_request.pathsを追加しただけです。workflow_dispatchも残しておけば、手動実行も引き続き可能です。

この構成により、以下の動作になります。

PRの変更内容blog_scraper スキャンsvg_to_png スキャン
blog_scraper/main.pyを修正実行される実行されない
svg_to_png/converter.pyを修正実行されない実行される
両方を修正実行される実行される
docs/のみ修正実行されない実行されない

モノレポで7つのパッケージがある場合、全パッケージをフルスキャンすると不要なAPI呼び出しと待ち時間が発生します。パスフィルターを使えば、PRで触ったコンポーネントだけをスキャンできるため、レビューのフィードバックが速くなり、API利用量も抑えられます

ハマりポイント:permissionsの配置

構築時に遭遇したハマりポイントを紹介します。

ベースワークフローのpermissionsをトップレベルに置くとstartup_failure

最初にベースワークフローのpermissionsワークフローのトップレベルに配置したところ、呼び出し元のワークフローがstartup_failureで即座に失敗しました。

# NG: トップレベルに配置すると startup_failure になる
permissions:
  contents: write
  pull-requests: write
  checks: write
  actions: read

jobs:
  scanoss-scan:
    ...

startup_failureはログが一切生成されないため、原因の特定に手間取ります。

呼び出し元にpermissionsを書かないとstartup_failure

ベースワークフローのpermissionsをジョブレベルに移動しても、呼び出し元ワークフローにpermissionsがないと同じくstartup_failureで失敗します。

reusable workflowでは、呼び出し元のpermissionsが上限となります。呼び出し元にpermissionsを書かない場合はリポジトリのデフォルト権限が適用されますが、SCANOSS Code Scan Actionが必要とする権限(contents: writechecks: write等)が不足する場合にstartup_failureが発生します。

解決策

2つの対応を同時に行います。

  1. ベースワークフローのpermissionsジョブレベルに配置する
  2. 呼び出し元ワークフローにもpermissions明示的に記述する

本記事のワークフロー例はすべてこの対応済みの構成です。

実行結果

workflow_dispatchで手動実行した結果です。

ワークフローステータス実行時間
SCANOSS Scan – blog_scrapersuccess40秒
SCANOSS Scan – svg_to_pngsuccess47秒

各コンポーネントが独立したワークフローランとして実行されます。GitHub Actions UIでは別々のワークフローとして表示されるため、どのコンポーネントのスキャンが失敗したかが一目でわかります。

コンポーネントの追加方法

新しいパッケージ(例: html_to_png)をスキャン対象に追加する場合、トリガーワークフローを1つ作成するだけです。ベースワークフローの変更は不要です。

# .github/workflows/scanoss-monorepo-html-to-png.yml
name: SCANOSS Scan - html_to_png

on:
  pull_request:
    paths:
      - 'application/tools/src/html_to_png/**'
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write
  checks: write
  actions: read

jobs:
  scan:
    uses: ./.github/workflows/scanoss-monorepo-base.yml
    with:
      scan_path: application/tools/src/html_to_png
    secrets: inherit

コピーしてscan_pathpathsを書き換えるだけなので、追加コストは低いです。

まとめ

SCANOSS GitHub Actionsのreusable workflowパターンを使い、モノレポでコンポーネント別にスキャンを実行する構成を紹介しました。

項目ポイント
scanPathの制約単一の相対パスのみ。複数パスやワイルドカードは非対応
公式推奨パターンreusable workflow(workflow_call)でベースワークフローを共通化
パスフィルター連携on.pull_request.pathsで変更コンポーネントだけスキャンを発火
permissionsベースワークフローはジョブレベル、呼び出し元にも明示的に記述
コンポーネント追加トリガーワークフローを1ファイル追加するだけ

参考資料

関連リンク

シリーズ記事

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。
エンジニア募集中!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です