diff --git a/.github/scripts/govulncheck-gate.sh b/.github/scripts/govulncheck-gate.sh new file mode 100755 index 0000000..35db0b2 --- /dev/null +++ b/.github/scripts/govulncheck-gate.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env sh +# govulncheck の結果に「引き上げ方針」を適用するゲート(CLAUDE.md「Go バージョンの引き上げ方針」)。 +# +# 到達可能な指摘なし → pass +# 到達可能な非 stdlib(依存モジュール)の指摘がある → fail(stdlib 例外を適用しない) +# 到達可能な stdlib が固定中のマイナー内のパッチで直る → fail(据え置く理由が無い) +# 到達可能な stdlib がマイナー跨ぎの引き上げを要する → warning で許容 +# +# 一律 warning にしていた頃は誰も読まず、固定版が3パッチ分の既知 CVE を抱えたまま +# 気づけなかった。だから同マイナー内で直るものだけは fail にする。 +# +# 判定は `-format json` の構造化出力で行う。テキスト要約の grep は +# - 件数1件で単数形になる +# - 約80桁で折り返す +# - 成分の並び順(module と stdlib)に依存する +# - Symbol/Package/Module の全セクションの `Fixed in:` を拾ってしまう +# という4つの罠があり、いずれも実際にバグを生んだ(LESSONS 参照)。 +# +# JSON の finding では +# 到達可能 = trace[0].function が存在する(テキストの "=== Symbol Results ===" と一致) +# 脆弱なモジュール = trace[0].module(stdlib なら "stdlib") +# trace は「脆弱な関数が先頭・自コードのエントリポイントが末尾」の +# 呼び出し経路。末尾を見ると自分のモジュール名を拾ってしまう。 +# 修正版 = fixed_version(stdlib は "v1.26.6" 形式=go 接頭辞は付かない) +# +# 使い方(モジュールディレクトリで実行する): +# .github/scripts/govulncheck-gate.sh <.go-version のパス> [判定対象の JSON ファイル] +# +# 第2引数を渡すと govulncheck を実行せず、その JSON を判定対象にする(テスト用)。 +set -eu + +VERSION_FILE="${1:?usage: govulncheck-gate.sh [captured-json-file]}" +CAPTURED="${2-}" + +MINOR=$(tr -d "[:space:]" < "$VERSION_FILE" | cut -d. -f1,2) + +if [ -n "$CAPTURED" ]; then + JSON=$(cat "$CAPTURED") +else + # govulncheck 自体の失敗(ネットワーク断・引数誤り等)と「脆弱性を検出した」を + # 区別する。-format json は脆弱性検出でも 0 を返すため、非 0 は道具の失敗。 + ERR=$(mktemp) + if ! JSON=$("$(go env GOPATH)/bin/govulncheck" -format json ./... 2>"$ERR"); then + echo "::error::govulncheck failed to run" + cat "$ERR" >&2 + rm -f "$ERR" + exit 1 + fi + rm -f "$ERR" +fi + +# 到達可能な finding を "\t" に落とす。出力は JSON の +# ストリーム(連結オブジェクト)なので -n '[inputs]' でまとめて読む。 +REACHABLE=$(printf '%s' "$JSON" | jq -rn ' + [inputs] + | map(select(has("finding")) | .finding) + | map(select((.trace // []) | length > 0 and (.[0] | has("function")))) + | map(((.trace[0].module) // "unknown") + "\t" + (.fixed_version // "")) + | unique | .[] +') + +[ -z "$REACHABLE" ] && exit 0 + +# ここから先は何かしら報告する。人が読める形をログに残す(判断には使わない)。 +# 到達可能な指摘が無い大多数のケースで2回スキャンしないよう、ここまで来てから実行する。 +if [ -z "$CAPTURED" ]; then + "$(go env GOPATH)/bin/govulncheck" ./... 2>&1 || true +fi + +# 依存モジュール側の到達可能な指摘は stdlib 例外の対象外。先に判定する。 +MODULES=$(printf '%s\n' "$REACHABLE" | awk -F'\t' '$1 != "stdlib" { print $1 }' | sort -u) +if [ -n "$MODULES" ]; then + echo "::error::Reachable vulnerabilities in modules you depend on. Update the dependency:" + printf '%s\n' "$MODULES" | sed 's/^/ /' + exit 1 +fi + +# 固定中のマイナー内のパッチで直る stdlib の指摘。stdlib の fixed_version は "v1.26.6"。 +PATCHABLE=$(printf '%s\n' "$REACHABLE" | awk -F'\t' -v m="v$MINOR." 'index($2, m) == 1 { print $2 }' | sort -u) +if [ -n "$PATCHABLE" ]; then + echo "::error::Reachable stdlib vulnerabilities are fixed within go${MINOR}. Bump .go-version to the latest go${MINOR}.x, run ./build.sh, and commit the binaries. Fixed in:" + printf '%s\n' "$PATCHABLE" | sed 's/^/ /' + exit 1 +fi + +echo "::warning::Tolerating reachable stdlib vulnerabilities that need a minor-version bump (see the Go upgrade policy in CLAUDE.md)" +exit 0 diff --git a/.github/scripts/govulncheck-gate.test.sh b/.github/scripts/govulncheck-gate.test.sh new file mode 100755 index 0000000..2a3fbb0 --- /dev/null +++ b/.github/scripts/govulncheck-gate.test.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env sh +# govulncheck-gate.sh の判定テーブルを、govulncheck -format json と同じ構造の +# フィクスチャで検証する。到達可能性は trace[0].function の有無で表す。 +set -eu + +cd "$(dirname "$0")" +GATE=./govulncheck-gate.sh +TMP=$(mktemp -d) +trap 'rm -rf "$TMP"' EXIT +FAILED=0 + +# finding <脆弱なモジュール> +# trace は govulncheck と同じ向き(脆弱な関数が先頭・自コードのエントリポイントが末尾)。 +finding() { + if [ "$4" = reachable ]; then + trace='[{"module":"'$3'","function":"Vulnerable"},{"module":"example.com/app","function":"main"}]' + else + trace='[{"module":"'$3'","version":"v0.0.0"}]' + fi + printf '{"finding":{"osv":"%s","fixed_version":"%s","trace":%s}}\n' "$1" "$2" "$trace" +} + +# run <期待終了コード> <期待出力パターン|-> +run() { + want_code="$1"; want_pat="$2" + printf '%s\n' "$3" > "$TMP/version" + printf '%s' "$4" > "$TMP/out.json" + + got=$("$GATE" "$TMP/version" "$TMP/out.json" 2>&1) && code=0 || code=$? + if [ "$code" -ne "$want_code" ]; then + echo "FAIL [$CASE] exit=$code want=$want_code"; echo " output: $got"; FAILED=1; return + fi + if [ "$want_pat" != "-" ] && ! printf '%s' "$got" | grep -q "$want_pat"; then + echo "FAIL [$CASE] output missing '$want_pat'"; echo " output: $got"; FAILED=1; return + fi + echo "ok [$CASE]" +} + +CASE="到達可能な指摘なし → pass" +run 0 "-" 1.26.8 "$(finding GO-1 v1.26.9 stdlib info)" + +CASE="到達可能 stdlib・同マイナー内で修正 → fail" +run 1 "::error::" 1.26.5 "$(finding GO-1 v1.26.6 stdlib reachable)" + +CASE="到達可能 stdlib が1件だけ・同マイナー内 → fail(単数形の罠を構造で回避)" +run 1 "Fixed in" 1.26.5 "$(finding GO-1 v1.26.6 stdlib reachable)" + +CASE="到達可能 stdlib・マイナー跨ぎが必要 → warning で許容" +run 0 "::warning::" 1.26.8 "$(finding GO-1 v1.27.2 stdlib reachable)" + +CASE="到達可能 stdlib はマイナー跨ぎ + 到達不能 stdlib が同マイナー内 → warning で許容" +run 0 "::warning::" 1.26.8 "$(finding GO-1 v1.27.2 stdlib reachable)$(finding GO-2 v1.26.9 stdlib info)" + +CASE="混在: 到達可能な依存モジュール + 到達可能 stdlib はマイナー跨ぎ → fail" +run 1 "modules you depend on" 1.26.8 "$(finding GO-1 v1.27.2 stdlib reachable)$(finding GO-2 v1.2.3 golang.org/x/text reachable)" + +CASE="到達可能な依存モジュールのみ → fail" +run 1 "modules you depend on" 1.26.8 "$(finding GO-1 v1.2.3 golang.org/x/text reachable)" + +CASE="到達不能な依存モジュールのみ → pass" +run 0 "-" 1.26.8 "$(finding GO-1 v1.2.3 golang.org/x/text info)" + +CASE="到達可能 stdlib が複数・一部が同マイナー内 → fail" +run 1 "::error::" 1.26.5 "$(finding GO-1 v1.27.2 stdlib reachable)$(finding GO-2 v1.26.6 stdlib reachable)" + +CASE="CRLF の .go-version でもマイナーを取り違えない" +printf '1.26.5\r\n' > "$TMP/version" +printf '%s' "$(finding GO-1 v1.26.6 stdlib reachable)" > "$TMP/out.json" +if "$GATE" "$TMP/version" "$TMP/out.json" >/dev/null 2>&1; then + echo "FAIL [$CASE] expected exit 1"; FAILED=1 +else + echo "ok [$CASE]" +fi + +CASE="finding が1件も無い(空出力)→ pass" +run 0 "-" 1.26.8 '{"config":{"protocol_version":"v1.0.0"}}' + +[ "$FAILED" -eq 0 ] && echo "--- all gate cases passed" || echo "--- FAILURES" +exit "$FAILED" diff --git a/.github/workflows/build-verify.yml b/.github/workflows/build-verify.yml index 4fdf1a4..c617063 100644 --- a/.github/workflows/build-verify.yml +++ b/.github/workflows/build-verify.yml @@ -17,6 +17,7 @@ on: - 'build.sh' - 'build.ps1' - '.go-version' + - '.github/scripts/**' - '.github/workflows/build-verify.yml' push: branches: [master] @@ -31,6 +32,7 @@ on: - 'build.sh' - 'build.ps1' - '.go-version' + - '.github/scripts/**' - '.github/workflows/build-verify.yml' # 決定論ビルドは Go ツールチェーンのパッチ版まで一致が必要。版の定義は @@ -39,6 +41,14 @@ on: # ビルドフラグ自体は build.sh に集約している(重複定義を避けるため)。 jobs: + # govulncheck ゲートの判定テーブル(単数/複数形・行折り返し・マイナー跨ぎ)を検証する。 + # ロジックは全プラグインジョブが共有するため、ここが唯一のテスト箇所。 + gate-logic: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: .github/scripts/govulncheck-gate.test.sh + github: runs-on: ubuntu-latest defaults: @@ -54,15 +64,7 @@ jobs: - name: govulncheck run: | go install golang.org/x/vuln/cmd/govulncheck@latest - OUTPUT=$("$(go env GOPATH)/bin/govulncheck" ./... 2>&1) || STATUS=$? - echo "$OUTPUT" - if [ "${STATUS:-0}" -ne 0 ]; then - if echo "$OUTPUT" | grep -q "Your code is affected by [0-9]* vulnerabilities from the Go standard library"; then - echo "::warning::Tolerating known toolchain vulnerabilities from pinned Go standard library" - else - exit "$STATUS" - fi - fi + "$GITHUB_WORKSPACE/.github/scripts/govulncheck-gate.sh" "$GITHUB_WORKSPACE/.go-version" - name: Deterministic rebuild run: ./build.sh github working-directory: . @@ -90,15 +92,7 @@ jobs: - name: govulncheck run: | go install golang.org/x/vuln/cmd/govulncheck@latest - OUTPUT=$("$(go env GOPATH)/bin/govulncheck" ./... 2>&1) || STATUS=$? - echo "$OUTPUT" - if [ "${STATUS:-0}" -ne 0 ]; then - if echo "$OUTPUT" | grep -q "Your code is affected by [0-9]* vulnerabilities from the Go standard library"; then - echo "::warning::Tolerating known toolchain vulnerabilities from pinned Go standard library" - else - exit "$STATUS" - fi - fi + "$GITHUB_WORKSPACE/.github/scripts/govulncheck-gate.sh" "$GITHUB_WORKSPACE/.go-version" - name: Deterministic rebuild run: ./build.sh validator working-directory: . @@ -126,15 +120,7 @@ jobs: - name: govulncheck run: | go install golang.org/x/vuln/cmd/govulncheck@latest - OUTPUT=$("$(go env GOPATH)/bin/govulncheck" ./... 2>&1) || STATUS=$? - echo "$OUTPUT" - if [ "${STATUS:-0}" -ne 0 ]; then - if echo "$OUTPUT" | grep -q "Your code is affected by [0-9]* vulnerabilities from the Go standard library"; then - echo "::warning::Tolerating known toolchain vulnerabilities from pinned Go standard library" - else - exit "$STATUS" - fi - fi + "$GITHUB_WORKSPACE/.github/scripts/govulncheck-gate.sh" "$GITHUB_WORKSPACE/.go-version" - name: Deterministic rebuild run: ./build.sh ast-grep working-directory: . @@ -162,15 +148,7 @@ jobs: - name: govulncheck run: | go install golang.org/x/vuln/cmd/govulncheck@latest - OUTPUT=$("$(go env GOPATH)/bin/govulncheck" ./... 2>&1) || STATUS=$? - echo "$OUTPUT" - if [ "${STATUS:-0}" -ne 0 ]; then - if echo "$OUTPUT" | grep -q "Your code is affected by [0-9]* vulnerabilities from the Go standard library"; then - echo "::warning::Tolerating known toolchain vulnerabilities from pinned Go standard library" - else - exit "$STATUS" - fi - fi + "$GITHUB_WORKSPACE/.github/scripts/govulncheck-gate.sh" "$GITHUB_WORKSPACE/.go-version" - name: Deterministic rebuild run: ./build.sh retro-status working-directory: . @@ -198,15 +176,7 @@ jobs: - name: govulncheck run: | go install golang.org/x/vuln/cmd/govulncheck@latest - OUTPUT=$("$(go env GOPATH)/bin/govulncheck" ./... 2>&1) || STATUS=$? - echo "$OUTPUT" - if [ "${STATUS:-0}" -ne 0 ]; then - if echo "$OUTPUT" | grep -q "Your code is affected by [0-9]* vulnerabilities from the Go standard library"; then - echo "::warning::Tolerating known toolchain vulnerabilities from pinned Go standard library" - else - exit "$STATUS" - fi - fi + "$GITHUB_WORKSPACE/.github/scripts/govulncheck-gate.sh" "$GITHUB_WORKSPACE/.go-version" - name: Deterministic rebuild run: ./build.sh go-lsp working-directory: . @@ -234,15 +204,7 @@ jobs: - name: govulncheck run: | go install golang.org/x/vuln/cmd/govulncheck@latest - OUTPUT=$("$(go env GOPATH)/bin/govulncheck" ./... 2>&1) || STATUS=$? - echo "$OUTPUT" - if [ "${STATUS:-0}" -ne 0 ]; then - if echo "$OUTPUT" | grep -q "Your code is affected by [0-9]* vulnerabilities from the Go standard library"; then - echo "::warning::Tolerating known toolchain vulnerabilities from pinned Go standard library" - else - exit "$STATUS" - fi - fi + "$GITHUB_WORKSPACE/.github/scripts/govulncheck-gate.sh" "$GITHUB_WORKSPACE/.go-version" - name: Deterministic rebuild run: ./build.sh settings-advisor working-directory: . @@ -270,15 +232,7 @@ jobs: - name: govulncheck run: | go install golang.org/x/vuln/cmd/govulncheck@latest - OUTPUT=$("$(go env GOPATH)/bin/govulncheck" ./... 2>&1) || STATUS=$? - echo "$OUTPUT" - if [ "${STATUS:-0}" -ne 0 ]; then - if echo "$OUTPUT" | grep -q "Your code is affected by [0-9]* vulnerabilities from the Go standard library"; then - echo "::warning::Tolerating known toolchain vulnerabilities from pinned Go standard library" - else - exit "$STATUS" - fi - fi + "$GITHUB_WORKSPACE/.github/scripts/govulncheck-gate.sh" "$GITHUB_WORKSPACE/.go-version" - name: Deterministic rebuild run: ./build.sh worktree-manager working-directory: . diff --git a/.go-version b/.go-version index 8fe00a5..25691b4 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.26.5 +1.26.8 diff --git a/AGENTS.md b/AGENTS.md index 95d9425..2ee9193 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -79,7 +79,7 @@ Go ソースを変更したら、リポジトリルートで対象を決定論 ./build.sh ``` -Windows PowerShell では同じ target を `./build.ps1` に渡します。決定論ビルドが前提とする Go のパッチ版は `.go-version` に定義され、`build.sh`/`build.ps1` が `GOTOOLCHAIN` で強制します(未取得なら Go が自動ダウンロード)。素の `go build` で焼いたバイナリはローカル Go 版によって別物になるため、必ずビルドスクリプト経由で再ビルドしてください。 +Windows PowerShell では同じ target を `./build.ps1` に渡します。決定論ビルドが前提とする Go のパッチ版は `.go-version` に定義され、`build.sh`/`build.ps1` が `GOTOOLCHAIN` で強制します(未取得なら Go が自動ダウンロード)。素の `go build` で焼いたバイナリはローカル Go 版によって別物になるため、必ずビルドスクリプト経由で再ビルドしてください。`.go-version` を独断で書き換えないこと。引き上げ条件は CLAUDE.md「Go バージョンの引き上げ方針」に定義され、条件1(固定中のマイナー内のパッチで直る stdlib 脆弱性)は CI の govulncheck が fail で通知します。 ## Verification and Review diff --git a/CLAUDE.md b/CLAUDE.md index 3b2faf5..4bf926e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,6 +30,19 @@ cd agy-plugin-kit/validator/src && go vet ./... && go test ./... **ソース変更時は必ず `./build.sh` で再ビルドしてコミット**(`agy plugin install` はビルドせず git 追跡バイナリをコピーするだけ)。決定論フラグは `build.sh` に、Go のパッチ版は `.go-version` に集約され(`build.sh`/`build.ps1`/CI が同じファイルを読む)、bit-identical になる。CI の stale 検出ゲート(`.github/workflows/build-verify.yml`)がこれを前提にする。 +## Go バージョンの引き上げ方針 + +固定版は `.go-version` の1箇所(`build.sh`/`build.ps1`/CI が読む)。**上げるのは以下のいずれかに当たる時だけ**で、「新しい版が出たから」では上げない。1回の引き上げは21バイナリの再ビルド=約 157MB の新規 blob を伴う。 + +1. **到達可能な stdlib 脆弱性が、固定中のマイナー内のパッチで修正済み** → そのマイナーの最新パッチへ。言語変更が無く再ビルドのみで済む。**CI の govulncheck がこのケースを fail させる**ので、検知は自動。 +2. **固定中のマイナーが EOL**(Go は最新2マイナーのみ patch。1.28 リリース時点で 1.26 が該当)→ サポート内マイナーへ移行。`go vet` の新チェックや挙動変更を見込んでテストを流す。 +3. 依存の `go.mod` 下限が固定版を超えた。 +4. 必要な言語 / stdlib 機能がある。 + +マイナー移行は **EOL 直前まで据え置く**(最新マイナーへの追従はしない)。 + +手順は `.go-version` を書き換えて `./build.sh`(全プラグイン)→ 21バイナリをコミット。`go.mod` の `go` ディレクティブは**言語の下限**であって固定版とは別の軸なので、引き上げに合わせて動かさない。 + ## 実機検証(tmux + agy) agy の対話セッションは PTY を要するため tmux 経由で起こす。クリーン install → ツール実行までを実環境で確認する。 diff --git a/LESSONS.md b/LESSONS.md index 6d8cf6a..c73896b 100644 --- a/LESSONS.md +++ b/LESSONS.md @@ -1,5 +1,31 @@ # LESSONS(実装知見ログ) +## 2026-09-12: govulncheck の判定はテキスト要約の grep をやめ `-format json` に切り替えた(PR #22) + +- 却下した案: テキスト要約の grep を直し続ける。単数形対応 → 成分の並び順対応 → セクション(Symbol/Package/Module)の切り分け、と当てていく。 +- 決め手: 同一ブロックで**レビュー3周連続**して別種のバグが出た。(1) 件数1件で単数形になる、(2) 約80桁で折り返す、(3) 要約の module/stdlib 成分の並び順に依存する、(4) `Fixed in:` の grep が `=== Symbol Results ===` 以外(到達不能な Package/Module セクション)まで拾う。(4) は「到達可能な stdlib はマイナー跨ぎ・到達不能な stdlib が同マイナー内」で誤 fail することを旧ゲートで実測(`exit=1`、正しくは warning)。テキスト解析には破綻面の上限が無い。`-format json` の finding は `trace[0].function` の有無で到達可能性が、`trace[0].module` で脆弱なモジュールが、`fixed_version` で修正版が構造的に取れ、到達可能3件がテキストの Symbol Results と完全一致することを実測確認した。これは自分で書いた前2エントリの「覆す条件」そのもの。 +- 覆す条件: govulncheck が `-format json` のスキーマを破壊的に変更した場合(`trace` の向き・`fixed_version` の形式が対象)。 + +**注意**: `trace` は**脆弱な関数が先頭・自コードのエントリポイントが末尾**。`trace | last | .module` と書くと自分のモジュール名を拾い、「依存モジュールに到達可能な脆弱性あり」と誤報する(実測で踏んだ)。JSON フィクスチャのテストは11件とも通っていたが、フィクスチャ側も同じ向きで間違えていたため検出できなかった——**構造化データに移しても、実データでの end-to-end 確認は省けない**。また stdlib の `fixed_version` は `v1.26.6` 形式で、テキストの `@go1.26.6` とは接頭辞が違う。 + +## 2026-09-12: bot の P1 は「主張」と「推奨」を分けて検証する — 主張は外れでも推奨が当たることがある(PR #22) + +- 却下した案: Codex の P1「混在スキャン(第三者モジュール到達可能 + stdlib はマイナー跨ぎ)が warning で素通りし依存側脆弱性を隠す」をそのまま真として、判定構造を作り直す。 +- 決め手: 主張は**現実装では成立しなかった**。`golang.org/x/vuln@v1.8.0/internal/scan/text.go` の `summary()` を読むと要約は `affected by vulnerabilities from [ module(s)][ and ]the Go standard library.` と組まれ、混在時は `from 1 module and the Go standard library` になる。当時の正規表現は `vulnerabilit(y|ies) from the Go standard library` の**連続一致**だったため混在文には当たらず、実フィクスチャで `exit 1`(正しく fail)を確認した。ただし「正しく動くのは偶然」で、成分の並びが stdlib 先頭になれば例外が誤適用される。実測: 並び替えフィクスチャを修正前版に通すと `exit=0`(依存側脆弱性を隠蔽)。よって推奨(module 成分を独立に判定)は採用し、主張は否定した。 +- 覆す条件: govulncheck が機械可読出力(`-json`)を安定提供し、要約文の解析をやめられる場合。 + +## 2026-09-12: govulncheck 出力を grep で判定するなら単数形と行折り返しを前提にする(PR #22 レビュー対応) + +- 却下した案: 要約行を `grep -q "vulnerabilities from the Go standard library"`(複数形リテラル)で拾い、判定ロジックを7ジョブにインラインで複製したまま置く。 +- 決め手: govulncheck の要約文は**件数で単数形になり**、かつ**約80桁で折り返す**。実出力で `This scan also found 0 vulnerabilities in packages you import and 1\nvulnerability in modules you require` を確認した(同じ文型が単数形・改行の両方を踏む)。複数形リテラルのままだと stdlib 指摘1件の時に判定を取りこぼし、「マイナー跨ぎが必要なので warning で許容」すべきケースが `exit $STATUS` に落ちて**全ジョブが fail する**。変異体テストで再現済み(複数形のみ版は単数2ケースが FAIL、折り返し正規化なし版は折り返し1ケースが FAIL)。またインライン7重複のままだとこの1文字の差を7箇所直す必要があり、テストも書けなかった。 +- 覆す条件: govulncheck が機械可読な出力(`-json` 等)を安定提供し、grep ベースの判定をやめられる場合。 + +## 2026-09-12: 固定 Go 版の引き上げ条件を「同マイナー内パッチで直る到達可能 stdlib 脆弱性」に置き、CI を warning から fail へ + +- 却下した案: (a) 引き上げ判断を人の裁量に委ね、govulncheck の stdlib 指摘は従来どおり一律 `::warning::` で許容し続ける。(b) 常に最新マイナーへ追従する。 +- 決め手: (a) は実測で失敗していた。CI は毎 PR で govulncheck を走らせていたのに warning は誰にも読まれず、固定版 1.26.5 は**到達可能な** stdlib 脆弱性3件(GO-2026-6218 `net/url` / 6090 `crypto/tls` / 5972 `encoding/asn1`、いずれも `ServeStdio`→`tls.Conn.Read`・`asn1.Unmarshal` の経路)を抱えたまま3パッチ遅れていた。1.26.8 では govulncheck が `No vulnerabilities found`。(b) は据え置きコストが実測で重い——1回の引き上げで21バイナリ再ビルド=約 157MB の新規 blob(`.git` は既に 322MB)で、年2回のマイナー移行はこれを2回払う。よって「同マイナー内のパッチで直るなら fail、マイナー跨ぎが要るものだけ warning」に絞り、マイナー移行は EOL 直前まで据え置く。 +- 覆す条件: バイナリを git にコミットしなくなった場合(引き上げコストが消えるため最新追従が合理的になる)。または Go が最新2マイナーというサポート範囲を変えた場合。 + ## 2026-09-12: Go ツールチェーン版を `.go-version` に集約し `GOTOOLCHAIN` で強制する - 却下した案: (a) 従来どおり「go 1.26.5 前提」をコメント・README に書くだけで運用する。(b) 固定自体をやめ、stale ゲートを bit-identical 比較からソースハッシュ照合へ変更する。 diff --git a/agy-plugin-kit/validator/bin/validator-darwin-arm64 b/agy-plugin-kit/validator/bin/validator-darwin-arm64 index 5439a1b..4fceefd 100755 Binary files a/agy-plugin-kit/validator/bin/validator-darwin-arm64 and b/agy-plugin-kit/validator/bin/validator-darwin-arm64 differ diff --git a/agy-plugin-kit/validator/bin/validator-linux-amd64 b/agy-plugin-kit/validator/bin/validator-linux-amd64 index f179f0f..e096ba6 100755 Binary files a/agy-plugin-kit/validator/bin/validator-linux-amd64 and b/agy-plugin-kit/validator/bin/validator-linux-amd64 differ diff --git a/agy-plugin-kit/validator/bin/validator.exe b/agy-plugin-kit/validator/bin/validator.exe index 04f47c3..2f49448 100755 Binary files a/agy-plugin-kit/validator/bin/validator.exe and b/agy-plugin-kit/validator/bin/validator.exe differ diff --git a/ast-grep/bin/ast-grep-darwin-arm64 b/ast-grep/bin/ast-grep-darwin-arm64 index a52e424..59a18f2 100755 Binary files a/ast-grep/bin/ast-grep-darwin-arm64 and b/ast-grep/bin/ast-grep-darwin-arm64 differ diff --git a/ast-grep/bin/ast-grep-linux-amd64 b/ast-grep/bin/ast-grep-linux-amd64 index 073a149..3b807bd 100755 Binary files a/ast-grep/bin/ast-grep-linux-amd64 and b/ast-grep/bin/ast-grep-linux-amd64 differ diff --git a/ast-grep/bin/ast-grep.exe b/ast-grep/bin/ast-grep.exe index 6636adc..d38f2a2 100755 Binary files a/ast-grep/bin/ast-grep.exe and b/ast-grep/bin/ast-grep.exe differ diff --git a/github/bin/github-darwin-arm64 b/github/bin/github-darwin-arm64 index 9fa8f5d..2b716e9 100755 Binary files a/github/bin/github-darwin-arm64 and b/github/bin/github-darwin-arm64 differ diff --git a/github/bin/github-linux-amd64 b/github/bin/github-linux-amd64 index cb0f95a..58641e3 100755 Binary files a/github/bin/github-linux-amd64 and b/github/bin/github-linux-amd64 differ diff --git a/github/bin/github.exe b/github/bin/github.exe index e5aced5..6c80686 100755 Binary files a/github/bin/github.exe and b/github/bin/github.exe differ diff --git a/go-lsp/bin/go-lsp-darwin-arm64 b/go-lsp/bin/go-lsp-darwin-arm64 index e57fa02..a59ac2a 100755 Binary files a/go-lsp/bin/go-lsp-darwin-arm64 and b/go-lsp/bin/go-lsp-darwin-arm64 differ diff --git a/go-lsp/bin/go-lsp-linux-amd64 b/go-lsp/bin/go-lsp-linux-amd64 index 51ddb74..76f3af8 100755 Binary files a/go-lsp/bin/go-lsp-linux-amd64 and b/go-lsp/bin/go-lsp-linux-amd64 differ diff --git a/go-lsp/bin/go-lsp.exe b/go-lsp/bin/go-lsp.exe index 81a549e..f2002b0 100755 Binary files a/go-lsp/bin/go-lsp.exe and b/go-lsp/bin/go-lsp.exe differ diff --git a/retro-status/bin/retro-status-darwin-arm64 b/retro-status/bin/retro-status-darwin-arm64 index 9412c24..3c54be8 100755 Binary files a/retro-status/bin/retro-status-darwin-arm64 and b/retro-status/bin/retro-status-darwin-arm64 differ diff --git a/retro-status/bin/retro-status-linux-amd64 b/retro-status/bin/retro-status-linux-amd64 index 150c740..13644f0 100755 Binary files a/retro-status/bin/retro-status-linux-amd64 and b/retro-status/bin/retro-status-linux-amd64 differ diff --git a/retro-status/bin/retro-status.exe b/retro-status/bin/retro-status.exe index 452a69e..0257709 100755 Binary files a/retro-status/bin/retro-status.exe and b/retro-status/bin/retro-status.exe differ diff --git a/settings-advisor/bin/settings-advisor-darwin-arm64 b/settings-advisor/bin/settings-advisor-darwin-arm64 index db8b972..2516b6c 100755 Binary files a/settings-advisor/bin/settings-advisor-darwin-arm64 and b/settings-advisor/bin/settings-advisor-darwin-arm64 differ diff --git a/settings-advisor/bin/settings-advisor-linux-amd64 b/settings-advisor/bin/settings-advisor-linux-amd64 index 9889061..4f01567 100755 Binary files a/settings-advisor/bin/settings-advisor-linux-amd64 and b/settings-advisor/bin/settings-advisor-linux-amd64 differ diff --git a/settings-advisor/bin/settings-advisor.exe b/settings-advisor/bin/settings-advisor.exe index e5299d9..25c12ad 100755 Binary files a/settings-advisor/bin/settings-advisor.exe and b/settings-advisor/bin/settings-advisor.exe differ diff --git a/worktree-manager/bin/worktree-manager-darwin-arm64 b/worktree-manager/bin/worktree-manager-darwin-arm64 index e02798e..b7b162b 100755 Binary files a/worktree-manager/bin/worktree-manager-darwin-arm64 and b/worktree-manager/bin/worktree-manager-darwin-arm64 differ diff --git a/worktree-manager/bin/worktree-manager-linux-amd64 b/worktree-manager/bin/worktree-manager-linux-amd64 index a776cb8..ea13609 100755 Binary files a/worktree-manager/bin/worktree-manager-linux-amd64 and b/worktree-manager/bin/worktree-manager-linux-amd64 differ diff --git a/worktree-manager/bin/worktree-manager.exe b/worktree-manager/bin/worktree-manager.exe index 46ad011..6f4fb7b 100755 Binary files a/worktree-manager/bin/worktree-manager.exe and b/worktree-manager/bin/worktree-manager.exe differ