From 9a6563f72cfd2eca56816c6084ce8be81b9ad9dc Mon Sep 17 00:00:00 2001 From: killertcell428 Date: Tue, 19 May 2026 12:17:36 +0900 Subject: [PATCH 1/2] =?UTF-8?q?security:=20scorecard=20alerts=20=E2=80=94?= =?UTF-8?q?=20fix=20#182=20paper-review=20token=20scope,=20pin=20#173=20fu?= =?UTF-8?q?zz=20base=20image,=20document=20#8/#179/#180/#181/#175=20accept?= =?UTF-8?q?ance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code Scanning sweep (2026-05-19): Fixes: - .github/workflows/paper-review.yml: move contents/issues/pull-requests write from top-level to job-level; top-level becomes contents:read (#182). - .clusterfuzzlite/Dockerfile: pin gcr.io/oss-fuzz-base/base-builder-python by sha256:e24e8e50... matching the digest-pin convention used in the main Dockerfile (#173). Governance documentation (docs/scorecard-governance-setup.html): - §1: document current branch-protection state and dismiss rationale for #8 (solo-dev: required_approving_review_count=0 is intentional). - §6.1 (new): acceptance policy for job-level contents:write — applies to #179 (release.yml), #180 (sync-zenn-qiita.yml), #181 (zenn-deploy-trigger.yml). Top-level contents:read remains mandatory. - §6.2 (new): acceptance policy for local-source pip install — applies to #175 (.clusterfuzzlite/build.sh). - §6.3: #174 (Dockerfile pip hash-pin) explicitly deferred. Audit report: - docs/scorecard-alerts-2026-05-19.html: per-alert triage with risk assessment, proposed fix, and dismiss rationale. Already dismissed via Code Scanning API: #8, #175, #179, #180, #181. #182 and #173 will close automatically on next Scorecard run. Deferred: #174 (hash-pin trade-off), #57 (OpenSSF badge). Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: killertcell428 --- .clusterfuzzlite/Dockerfile | 2 +- .github/workflows/paper-review.yml | 8 +- docs/scorecard-alerts-2026-05-19.html | 351 ++++++++++++++++++++++++++ docs/scorecard-governance-setup.html | 124 +++++++++ 4 files changed, 481 insertions(+), 4 deletions(-) create mode 100644 docs/scorecard-alerts-2026-05-19.html diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile index b9844a4..862498e 100644 --- a/.clusterfuzzlite/Dockerfile +++ b/.clusterfuzzlite/Dockerfile @@ -1,4 +1,4 @@ -FROM gcr.io/oss-fuzz-base/base-builder-python +FROM gcr.io/oss-fuzz-base/base-builder-python@sha256:e24e8e50612617101dd10038502f68268ab45f31d79a3722c230464277a951b3 # Install minimal build deps RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/.github/workflows/paper-review.yml b/.github/workflows/paper-review.yml index 2103394..0b01624 100644 --- a/.github/workflows/paper-review.yml +++ b/.github/workflows/paper-review.yml @@ -29,9 +29,7 @@ on: default: "10" permissions: - contents: write # to commit state.json + pending stubs - issues: write # to file the daily summary issue - pull-requests: write # so the bot can open a PR with the new pending files + contents: read concurrency: group: paper-review @@ -41,6 +39,10 @@ jobs: review: name: Review 10 papers and file pending candidates runs-on: ubuntu-latest + permissions: + contents: write # commit state.json + pending stubs to bot branch + issues: write # file daily summary issue + pull-requests: write # open bot PR with new pending files steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 diff --git a/docs/scorecard-alerts-2026-05-19.html b/docs/scorecard-alerts-2026-05-19.html new file mode 100644 index 0000000..acdf477 --- /dev/null +++ b/docs/scorecard-alerts-2026-05-19.html @@ -0,0 +1,351 @@ + + + + +Code Scanning アラート精査レポート — 2026-05-19 + + + + + +

Code Scanning アラート精査レポート

+
対象: killertcell428/aigis · 取得日 2026-05-19 · 検出元 Scorecard · 件数 9 (High 5 / Medium 3 / Low 1)
+ +

1. エグゼクティブサマリ

+ +
+
5
High
+
3
Medium
+
1
Low
+
3
即時修正推奨
+
3
改善余地あり
+
3
運用判断 / 受容
+
+ +

9件すべて Scorecard が機械的に検出したセキュリティ・ベストプラクティス違反であり、 +実害のある脆弱性ではない。ただし #182 (paper-review.yml の top-level write 権限) +は GITHUB_TOKEN を最小権限化する観点で真の修正が必要。 +他の High 3件は既に job-level スコープを切っており、Scorecard の検出ロジックの粒度の問題で +残っている false-positive 寄りのもの。Medium 3件 (Pinned-Dependencies) は OSS-Fuzz 慣行と +噛み合わない部分があり、コスト対効果の判断が必要。

+ +

推奨対応順

+
    +
  1. 即対応 — #182 paper-review.yml の権限を job-level に移し top-level を contents: read
  2. +
  3. 即対応 — #173 .clusterfuzzlite/Dockerfile の base image を digest pin
  4. +
  5. 近日対応 — #8 master の Branch Protection ルール設定 (docs/scorecard-governance-setup.html の続編)
  6. +
  7. 判断 → ドキュメント化 — #179/#180/#181 (job-level write は許容方針として記録)
  8. +
  9. 判断 → ドキュメント化 — #174/#175 (pip hash pinning は CI 維持コスト次第)
  10. +
  11. 後回し可 — #57 CII Best Practices badge の取得
  12. +
+ +

2. アラート一覧

+ + + + + + + + + + + + + + + + +
#カテゴリSevファイル判定
#182Token-PermissionsHigh.github/workflows/paper-review.yml:32修正必須
#181Token-PermissionsHigh.github/workflows/zenn-deploy-trigger.yml:14運用判断 (受容可)
#180Token-PermissionsHigh.github/workflows/sync-zenn-qiita.yml:16運用判断 (受容可)
#179Token-PermissionsHigh.github/workflows/release.yml:134運用判断 (受容可)
#8Branch-ProtectionHigh(repo settings)設定追加推奨
#175Pinned-DependenciesMedium.clusterfuzzlite/build.sh:8低優先 (OSS-Fuzz 環境)
#174Pinned-DependenciesMediumDockerfile:6判断 (hash pin コスト)
#173Pinned-DependenciesMedium.clusterfuzzlite/Dockerfile:1修正推奨 (low cost)
#57CII-Best-PracticesLow(badge 未登録)後回し可
+ +

3. アラート別の詳細と修正提案

+ + +
+

#182 Token-Permissions 修正必須

+
+
ファイル
.github/workflows/paper-review.yml:31-34
+
原因
top-level で contents: write / issues: write / pull-requests: write を付与している。Scorecard は top-level write 権限を「ワークフロー内のあらゆる action にトークンが流れる」として High 判定。
+
リスク
Anthropic API キー込みのワークフローで、悪意のある依存 (uv / setup-python のサプライチェーン経由) があった場合、トークン奪取によりリポジトリ書き込みまで連鎖し得る。
+
+ + 修正案 — top-level を read に、job-level で必要権限を付与 +
# 31-34行目を以下に置換
+permissions:
+  contents: read
+
+concurrency:
+  group: paper-review
+  cancel-in-progress: false
+
+jobs:
+  review:
+    name: Review 10 papers and file pending candidates
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write       # commit state.json + pending stubs to bot branch
+      issues: write         # file daily summary issue
+      pull-requests: write  # open bot PR
+    steps:
+      ...
+
+ +
+ 確認ポイント +
    +
  • job-level permissions: を書いた瞬間、その job 内では top-level が無効化され job-level だけが効く。差し替えで実行影響なし。
  • +
  • このワークフローは job が review 1個だけなので機械的に移動するだけで完了。
  • +
+
+
+ + +
+

#181 Token-Permissions 運用判断 — 受容可

+
+
ファイル
.github/workflows/zenn-deploy-trigger.yml:13-14
+
現状
top-level は既に contents: read。job-level で contents: write を最小限付与済 (push の為に必須)。
+
Scorecard 判定理由
Scorecard は あらゆる write 出現を High カウントするため、job-level でも残る。これはツール側の設計で、現状の構成は GitHub Actions のベストプラクティスに完全準拠している。
+
+ + 対応案 +

3案あり、どれを選ぶかは運用ポリシー次第。

+
    +
  1. 受容してドキュメント化 (推奨): docs/scorecard-governance-setup.html に「job-level write は許容、top-level write は禁止」の方針を追記し、本アラートを Scorecard 側で dismiss する。
  2. +
  3. Deploy Key 化: GITHUB_TOKEN をやめ、専用 SSH デプロイキーで push する。contents: 権限自体を不要にできるが、シークレット管理コストが増える。empty commit を打つだけのワークフローには過剰。
  4. +
  5. 外部 App Token 化: GitHub App を作って actions/create-github-app-token で発行。最小権限を厳密化できるが、運用が重い。
  6. +
+
+ + +
+

#180 Token-Permissions 運用判断 — 受容可

+
+
ファイル
.github/workflows/sync-zenn-qiita.yml:15-16
+
現状
#181 と同様、top-level contents: read + job-level contents: write の正しい構成。
+
用途
Zenn → Qiita 変換後の public/ ディレクトリを bot push し、Qiita CLI で publish。
+
+ 対応案 +

#181 と同じく、受容+ドキュメント化が現実解。Qiita publish 部分は別途 QIITA_TOKEN シークレットを使うので、GITHUB_TOKEN 側を厳しく絞るインセンティブは低い。

+
+ + +
+

#179 Token-Permissions 運用判断 — 受容可 / 一部最適化余地

+
+
ファイル
.github/workflows/release.yml:133-134 (github-release job)
+
現状
top-level contents: read + github-release job のみ contents: write (Release 作成のため必須)。build / publish-pypicontents: read + OIDC id-token: write で正しくスコープ済。
+
Scorecard 判定理由
job-level の contents: write 1箇所を機械的に検出。
+
+ 対応案 +
    +
  • 受容 (推奨): PyPI publish は OIDC 化、tag → Release のみ contents: write という構成は GitHub 公式 release workflow の標準形。CHANGELOG.md / CLAUDE.md の release 規約とも一致しているため、変更すべきではない。
  • +
  • 代替: softprops/action-gh-releaseGITHUB_TOKEN ではなく App Token で動かせば contents: write を完全に剥がせるが、PR/tag フローの監査トレイル (release が誰名義で作られたか) が変わる。慎重に。
  • +
+
+ + +
+

#8 Branch-Protection 設定追加推奨

+
+
対象
repository settings (no file)
+
原因
master ブランチに Branch Protection ルールが未設定 (または Scorecard が読み取れる範囲では未設定)。
+
リスク
direct push / force push / CI 未通過マージが理論上可能。CLAUDE.md の release プロセス (PR マージ → tag) を制度的に強制できない。
+
+ 推奨ルール (Settings → Branches → Add rule) +
    +
  • Require a pull request before merging (1 approval)
  • +
  • Require status checks: tests, codeql, scorecard
  • +
  • Require branches to be up to date before merging
  • +
  • Require signed commits (任意、CLAUDE.md の --no-gpg-sign 禁止と整合)
  • +
  • Do not allow bypassing the above settings (admin も含めて適用)
  • +
  • Restrict force push / deletion
  • +
+

※ 既存の docs/scorecard-governance-setup.html に該当章があるかは要確認。なければ追記。

+
+ + +
+

#175 Pinned-Dependencies 低優先

+
+
ファイル
.clusterfuzzlite/build.sh:8 (pip3 install --no-cache-dir .)
+
原因
aigis 自身 (ローカルパス .) の install で --require-hashes 等のハッシュ検証なし。
+
リスク評価
ローカルソースを install しているため通常意味でのサプライチェーンリスクは低い。Scorecard はチェックロジック上 pip install の出現自体を機械的に検出。
+
+ 対応案 +

このまま受容で良い。ClusterFuzzLite の build はホスト fuzz 環境内で完結し、wheel/sdist を index から取らないため攻撃面が無い。Scorecard 側で dismiss reason = "No PyPI download — installs local source only" として閉じる。

+
+ + +
+

#174 Pinned-Dependencies 判断 — hash pin か受容か

+
+
ファイル
Dockerfile:6 (pip install ... 'pip==26.1.1' 'build==1.5.0')
+
現状
バージョンは pin 済だが、Scorecard が要求するのは --require-hashes + --no-deps による SHA-256 hash pinning。
+
+ 案A — 完全 hash pin (Scorecard を Pass にする) +
COPY requirements-build.txt /tmp/
+RUN pip install --no-cache-dir --require-hashes -r /tmp/requirements-build.txt
+
+

requirements-build.txt:

+
pip==26.1.1 \
+    --hash=sha256:<...>
+build==1.5.0 \
+    --hash=sha256:<...>
+
+

+ pip-compile --generate-hashes でハッシュ生成、依存 update のたびに pin を更新する CI が必要。

+ + 案B — 受容 (推奨) +

build stage の依存は pipbuild の2つだけで、いずれも PyPI 公式パッケージ。hash pin の運用コストの方が高い可能性。Dependabot で version pin を継続管理する方が ROI が高い。

+
+ + +
+

#173 Pinned-Dependencies 修正推奨

+
+
ファイル
.clusterfuzzlite/Dockerfile:1
+
原因
FROM gcr.io/oss-fuzz-base/base-builder-python がタグなし・digest なし (=latest 相当)。
+
リスク
base image が更新されると fuzz harness の build 結果が変わる (再現性無し)。供給元 (Google OSS-Fuzz) は信頼できるが「再現可能ビルド」観点で問題。
+
+ 修正案 +
# 最新 digest を取得して固定
+FROM gcr.io/oss-fuzz-base/base-builder-python@sha256:<digest>
+
+

本体 Dockerfile は既に python:3.14-slim@sha256:7a500125... で pin 済なので、同じ流儀に合わせるだけ。digest 取得は次のいずれか:

+
    +
  • docker pull gcr.io/oss-fuzz-base/base-builder-python && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/oss-fuzz-base/base-builder-python
  • +
  • Google Container Registry の Web UI で確認
  • +
+

運用: Dependabot は GCR の digest 更新も検知できるよう package-ecosystem: docker.github/dependabot.yml に追加 (まだ無ければ)。

+
+ + +
+

#57 CII-Best-Practices 後回し可

+
+
対象
OpenSSF Best Practices Badge (旧 CII Best Practices)
+
原因
bestpractices.dev での self-certification 未取得。
+
+ 対応案 +

30〜60分の self-assessment フォーム記入で Passing badge は取得可能。README に bestpractices.dev のバッジを貼ると外部信頼度↑。docs/openssf-best-practices.md 既存ドキュメントの内容を踏まえると、すでにかなりの基準を満たしているはず。優先度低だがコストも低いので、空き時間にやれる。

+
+ +

4. 実装プラン (採用された場合のチェックリスト)

+ +
+Phase 1 — 1 PR で完結する低リスク変更 +
    +
  • [ ] .github/workflows/paper-review.yml の permissions を job-level に移動 (#182)
  • +
  • [ ] .clusterfuzzlite/Dockerfile の base image を digest pin (#173)
  • +
  • [ ] CHANGELOG [Unreleased] に "ci: tighten paper-review GITHUB_TOKEN scope; pin clusterfuzzlite base image" を追加
  • +
+
+ +
+Phase 2 — リポジトリ設定 (UI 操作) +
    +
  • [ ] master の Branch Protection 設定 (#8) — Settings → Branches
  • +
  • [ ] docs/scorecard-governance-setup.html に方針を追記 (job-level write 受容、top-level write 禁止)
  • +
  • [ ] #179/#180/#181 を Scorecard 側で dismiss (reason: "acceptable risk per governance policy")
  • +
+
+ +
+Phase 3 — 判断が必要な改善 +
    +
  • [ ] Dockerfile の pip hash pin 化 (#174) — 採用するか否か決定
  • +
  • [ ] .clusterfuzzlite/build.sh の扱い (#175) — dismiss か no-op か決定
  • +
  • [ ] OpenSSF Best Practices badge 申請 (#57)
  • +
+
+ +

5. 参考

+ + + + diff --git a/docs/scorecard-governance-setup.html b/docs/scorecard-governance-setup.html index 353d20c..b1a4bb3 100644 --- a/docs/scorecard-governance-setup.html +++ b/docs/scorecard-governance-setup.html @@ -69,6 +69,8 @@

サマリ

CodeReviewinfo運用変更BranchProtection と一緒に解決 CIIBestPracticesinfo30分〜数時間OSS 公開ならやる価値あり Fuzzinginfo数日後回しでOK +Token-Permissions (job-level)info—受容 (§6) +Pinned-Dependencies (local install)info—受容 (§6) @@ -124,6 +126,30 @@

手順(GitHub UI)

注意: 1 人開発のリポでも approval=1 を要求するとマージできなくなる場合があります。その場合は approval を 0 にしつつ status checks のみ必須化する、または GitHub の "Allow specified actors to bypass required pull requests" を使ってください。 +

現状(2026-05-19 時点)と Scorecard alert #8 の扱い

+ +

本リポは既に以下の Branch Protection を有効化済(gh api repos/killertcell428/aigis/branches/master/protection で確認):

+ +
    +
  • ✅ Required status checks (strict): Lint & Type Check, Test / Python 3.11, Test / Python 3.12
  • +
  • ✅ Required signatures (signed commits)
  • +
  • ✅ Enforce admins
  • +
  • ✅ Required linear history
  • +
  • ✅ Required conversation resolution
  • +
  • ✅ allow_force_pushes = false / allow_deletions = false
  • +
  • ✅ dismiss_stale_reviews = true / require_code_owner_reviews = true
  • +
  • ⚠️ required_approving_review_count = 01 人開発のため意図的
  • +
+ +

Scorecard alert #8 Branch-Protection (High) が残っているのは、最後の required_approving_review_count = 0 に起因する。これは「自分の PR を自分でマージできる必要がある」というソロ開発の現実的制約で、外部コントリビュータが現れたら approval=1 に上げる方針。Won't fix として dismiss する

+ +

dismiss 文言テンプレ:

+
Won't fix — solo developer repo. Branch protection enforces status
+checks, signed commits, linear history, and admin enforcement; only
+required_approving_review_count is 0 (would block all merges otherwise).
+Will raise to 1 once a second maintainer joins.
+See docs/scorecard-governance-setup.html §1.
+

2. Maintained — リポジトリ作成から90日未満

Scorecard 指摘: Repository was created within the last 90 days

@@ -196,6 +222,104 @@

推奨アプローチ: Atheris (Python ネイティブ)

後回しでOK。先に他の項目を片付けてから検討。

+

6. 受容方針 — Token-Permissions (job-level) と Pinned-Dependencies (local install)

+ +

+Scorecard が High / Medium で機械的に検出するが、構成上「これ以上絞れない/絞ると別のリスクが増える」種類のアラートを明示的に受容する方針を以下に定める。新しいアラートが同じカテゴリで上がった場合、本セクションに照らして dismiss 可否を判断する。 +

+ +

6.1 Token-Permissions: job-level contents: write は許容、top-level は禁止

+ +

方針:

+
    +
  • すべての workflow は top-level で permissions: contents: read(または最小権限)を設定する。
  • +
  • write 権限は 必要な job の permissions: ブロックでのみ付与する。
  • +
  • 上記を満たしていれば、Scorecard が job-level write を High として検出しても dismiss 可
  • +
+ +

根拠:

+
    +
  • GitHub Actions の GITHUB_TOKEN は job 単位でスコープされるため、job-level に絞った時点で他 job への漏出は防げる。
  • +
  • Scorecard の Token-Permissions チェックは write の出現を機械的にカウントするため、正しいスコープであっても High として残る既知の挙動。
  • +
  • これを完全に消すには Deploy Key / GitHub App Token に置き換える必要があるが、シークレット管理コスト・監査トレイル変更のデメリットが運用上のリスク低減を上回る。
  • +
+ +

対応済アラート:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Alertファイル用途判断
#179.github/workflows/release.yml:134github-release job — GitHub Release 作成のため contents: write 必須受容 (build/publish-pypi job は OIDC 化済で contents: read)
#180.github/workflows/sync-zenn-qiita.yml:16Zenn→Qiita 変換後の public/ commit + push受容
#181.github/workflows/zenn-deploy-trigger.yml:14Zenn deploy トリガーの empty commit push受容
+ +

dismiss 文言テンプレ(Code scanning UI で使用):

+
Won't fix — job-level permissions are correctly scoped per
+docs/scorecard-governance-setup.html §6.1.
+Top-level is contents:read; this job's write scope is the
+minimum required for its function.
+ +

6.2 Pinned-Dependencies: ローカルソースの pip install は許容

+ +

方針:

+
    +
  • PyPI / 外部 registry から取得する依存は version pin を必須とし、可能なら hash pin(--require-hashes)を導入する。
  • +
  • ローカルソース (pip install .) は hash pin 不要として受容する。
  • +
  • コンテナイメージは digest pin を必須とする (§ Dockerfile / .clusterfuzzlite/Dockerfile ともに digest pin 済)。
  • +
+ +

根拠:

+
    +
  • ローカルソース install はネットワークから wheel/sdist を取得しないため、サプライチェーン経由の改ざんリスクが存在しない。
  • +
  • fuzz harness の build 環境内で完結しており、攻撃面が無い。
  • +
+ +

対応済アラート:

+ + + + + + + + + + + + + +
Alertファイル内容判断
#175.clusterfuzzlite/build.sh:8pip3 install --no-cache-dir . — ローカル aigis ソースの install受容 (ネットワーク取得なし)
+ +

dismiss 文言テンプレ:

+
Won't fix — installs local source only (no PyPI download),
+no supply-chain surface. See docs/scorecard-governance-setup.html §6.2.
+ +

6.3 判断保留

+ +

以下は受容も修正もせず、運用コストとのトレードオフを継続検討する:

+
    +
  • #174 Dockerfile:6pip install pip==26.1.1 build==1.5.0 の hash pin 化。pip-compile --generate-hashes 運用が現実的か要検討。
  • +
+

完了確認

すべて設定後、Scorecard を再実行して結果を確認できます:

From 7d993afea2cb826cd060affae02c9ab9cc78e828 Mon Sep 17 00:00:00 2001 From: killertcell428 Date: Tue, 19 May 2026 13:37:42 +0900 Subject: [PATCH 2/2] chore: add DCO sign-off for security scorecard sweep PR Signed-off-by: killertcell428