semgrep ci --config=autoでコード変更なしにmainが赤くなる
※本記事にはアフィリエイトリンクを含む場合があります。内容は広告の有無に影響されません。
結論
semgrep ci --config=autoはSemgrepレジストリのコミュニティ規則を実行のたびに取得するため、リポジトリを一切変更しなくても上流が規則を追加した日だけmainブランチが赤くなる。
結論
**semgrep ci --config=autoはSemgrepレジストリのコミュニティ規則(実測1074件)を実行のたびに取得するため、リポジトリのコードを一切変更していなくても、上流が新しい規則を追加した日だけCIのmainブランチが赤くなる。**旧構成ではSEMGREP_RULES環境変数で5つのルールセットを宣言していたが、実行コマンド自体には--config=autoを渡していたためその宣言は読まれず、常にレジストリ全件が走っていた。対処は規則セットを--config=p/xxxで明示列挙し、Semgrepのコンテナイメージをdigestで固定することだった。
症状
キミテラス-v2のsecurity.ymlはSAST(静的解析)にSemgrepを使っている。修正前(abb0ba6時点)の構成は次の形だった。
semgrep:
name: SAST (Semgrep)
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v6
- run: semgrep ci --config=auto --sarif --output=semgrep.sarif
env:
SEMGREP_RULES: >-
p/typescript
p/javascript
p/nodejs
p/owasp-top-ten
p/security-audit
一見、SEMGREP_RULESで5つのルールセットに絞っているように見える。だがsemgrep ciの実行コマンド自体に渡しているのは--config=autoで、--config=autoが指定されるとSemgrepはSemgrepレジストリのコミュニティ規則を都度取得して実行する(実測1074件)。SEMGREP_RULES環境変数の宣言はここでは読まれない。コンテナイメージもsemgrep/semgrepとタグ無し(=latest)のまま指定されていた。
2026-07、Semgrepレジストリにsupply-chain系の新しい規則が追加され、それだけで41件がblockingとして検出されmainが恒常的に赤くなった。リポジトリのコードは一行も変わっていない。
原因
原因は2つ重なっている。
--config=autoがSEMGREP_RULESの宣言を無効化していた。 宣言した5つのルールセットは実際には走っておらず、常にレジストリ全件(1074件)が対象になっていた。宣言と実挙動が乖離した状態が続いていた。- Semgrep OSSには重大度フィルタが無い。 検出されたものは全件blockingとして扱われるため、ゲートの合否は「どの規則を走らせるか」だけで決まる。
--config=autoはSemgrepレジストリの中身に依存するため、レジストリ側が規則を追加・変更した瞬間にゲートの合否が変わりうる。コンテナイメージもタグ無し(latest)だったため、Semgrep自体のバージョンアップでも挙動が変わりうる状態だった。
この2つの結果、「リポジトリを一切変更しなくても上流が規則を足した日にmainが赤くなる」という、コードレビューでは検知できない構造になっていた。
直す
対処は3段になっている。
① 規則セットを明示列挙し、エンジンをdigestで固定する。
semgrep:
name: SAST (Semgrep)
runs-on: ubuntu-latest
container:
image: semgrep/semgrep@sha256:bdf7013b2c3634a487671158da77c554f531742326b543a9464d2adf6c433ac8 # 1.171.0
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- run: >-
semgrep ci --sarif --output=semgrep.sarif
--config=p/typescript
--config=p/javascript
--config=p/nodejs
--config=p/owasp-top-ten
--config=p/security-audit
--config=p/github-actions
--exclude-rule=package_managers.pnpm.pnpm-missing-minimum-release-age.pnpm-minimum-release-age
--exclude-rule=package_managers.pnpm.pnpm-block-exotic-sub-dependencies.pnpm-block-exotic-sub-dependencies
--exclude-rule=package_managers.pnpm.pnpm-trust-policy.pnpm-trust-policy
--exclude-rule=terraform.gcp.security.gcp-cloud-storage-logging.gcp-cloud-storage-logging
--config=autoは消え、代わりに--config=p/xxxを6つ明示している。コンテナイメージもlatestではなくdigest固定に変えた。p/github-actionsを新たに加えているのは、uses:のSHA pinが退行していないかを継続的に検知するため。
--exclude-ruleで外している4件には、それぞれ理由がコードコメントとして残っている。pnpm-minimum-release-ageとpnpm-block-exotic-sub-dependenciesは「pnpm 11の既定で既に有効な設定への誤検知」、pnpm-trust-policyは「--frozen-lockfileでも既存ロック全件に再適用され、上流都合だけでリポジトリ無変更のままCIが落ちうるため意図的に不採用」、terraformの1件は「実指摘だが対応は別issueで追跡中」——除外は無言で足さず、理由を書いた上で行われている。
② --config=autoは週次限定の非blockingジョブに分離する。
semgrep-discovery:
name: SAST Discovery (Semgrep auto, non-blocking)
runs-on: ubuntu-latest
if: github.event_name == 'schedule'
continue-on-error: true
container:
image: semgrep/semgrep@sha256:bdf7013b2c3634a487671158da77c554f531742326b543a9464d2adf6c433ac8 # 1.171.0
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- run: semgrep ci --config=auto --sarif --output=semgrep-auto.sarif
continue-on-error: true
--config=autoの広い網自体は捨てていない。ただしblocking判定からは外し、週1回のscheduleだけで動く非blockingジョブに移した。ここでの検出はmainを止めず、code scanningアラートとして残り続ける形にした。
③ uses:をSHA pinする。 同じコミットで.github/workflows配下のuses:を合計35箇所(security.yml13箇所+ci.yml22箇所)、40桁SHA+バージョンコメントへ変更している。actions/dependency-review-action@v5はタグではなくブランチ参照だったため、他のタグ参照より更に可変性が高かった。
再発防止
この構造は「規則セットを絞ったつもりでも、実行コマンドの他のフラグに上書きされていないか」を確認しないと再発する。envでルールセットを宣言する形はSemgrepの--config=auto実行時には読まれず、絞り込みは--configフラグとして渡す必要がある。また重大度フィルタの無いツールをblockingゲートに使う場合、規則セットの取得元(autoのようにレジストリへ都度アクセスするか、p/xxxのように固定セットを指定するか)自体が、コードを変更しなくてもゲートの合否を左右する変数になる。p/xxxを明示列挙しても完全な決定論にはならない(scan時にレジストリから内容を取得する点はautoと同じ)ことを踏まえたうえで、「どこまでをblockingで許容し、どこからをdiscoveryへ逃がすか」をあらかじめ線引きしておくと、同じ形の恒常赤化を避けやすい。
よくある質問
Q1なぜコードを変更していないのにmainが赤くなったのですか?
semgrep ci --config=autoがSemgrepレジストリのコミュニティ規則(実測1074件)を実行のたびに取得しており、2026-07に上流でsupply-chain系の新規則が追加されたことで、リポジトリを一切変更していなくても41件がblockingとして検出されmainが赤くなったため。
Q2SEMGREP_RULESで規則セットを宣言していたのに効かなかったのはなぜですか?
旧構成ではenv: SEMGREP_RULESで5つのルールセットを宣言しながら、実行コマンドには--config=autoを渡していたため、その宣言はSemgrepに読まれず常にレジストリ全件(1074件)が走っていた。宣言と実際の挙動が乖離していた。
Q3対処後は完全に決定的になりましたか?
いいえ。p/*の各ルールセット自体もscan時にSemgrepレジストリから取得され中身は上流で更新されうるため、完全な決定論ではない。実際に移行時もp/owasp-top-ten由来のterraform規則3件が新たに顕在化した。
Q4--config=autoは完全に廃止したのですか?
いいえ。blocking判定からは外したが、週次scheduleだけで走るsemgrep-discoveryジョブとして残した。continue-on-error: trueで非blockingにし、新規則の指摘をcode scanningアラートとして可視化する役割に変えた。
Q5pnpmの規則を3件除外しているのはなぜですか?
pnpm-minimum-release-ageとpnpm-block-exotic-sub-dependenciesはpnpm 11の既定で既に有効なため誤検知と判断した。pnpm-trust-policyは--frozen-lockfileでも既存ロック全件に再適用され、上流都合だけでCIが落ちうるため意図的に採用しないことにした。
確認した環境
- semgrep/semgrepイメージ 1.171.0(digest固定)/ actions/checkout v6.1.0
- 2026-07-25 にキミテラス-v2のCIで対処(旧構成では2026-07に上流の規則追加でmain恒常赤化)
この記事の根拠
- YAMLファイル 27〜45行目コミット abb0ba6
- YAMLファイル 31〜96行目コミット 48f38e3
- YAMLファイル 98〜120行目コミット 48f38e3
- YAMLファイル 9〜32行目コミット 48f38e3
- YAMLファイルコミット 48f38e3
本文の主張は、上の記録に書かれていることだけです。運用しているリポジトリは非公開のため リンクは張れませんが、どのファイルの何行目を、どのコミット時点で見て書いたかは 記事ごとに残しています。推測で書いた箇所はありません。