Skip to content

Commit 1a25368

Browse files
authored
Merge pull request #772 from hideyukiMORI/chore/deps-floors-and-mcp-constraint
chore(deps): 直接依存の下限をセキュリティ床に上げ mcp を 1.x に固定する (v1.8.170)
2 parents 7ca689b + b7903a6 commit 1a25368

5 files changed

Lines changed: 152 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,49 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
88
99
---
1010

11-
## [1.8.169] — 2026-08-12
11+
## [1.8.170] — 2026-08-12
12+
13+
依存の下限をセキュリティ床として引き上げ、mcp を 1.x 系に固定した。
14+
15+
### ⚠️ 公開メタデータの変更 — 利用者の解決結果が変わります
16+
17+
直接依存の**下限を引き上げた**ため、`requires-dist`(PyPI 配布物の依存要件)が変わります。
18+
本バージョンをインストールすると、以下より古い版は**解決されなくなります**
19+
20+
| 依存 | 変更 | 引き上げた理由(advisory ID) |
21+
|---|---|---|
22+
| `mcp` | `>=1.0`**`>=1.28.1`** | PYSEC-2026-3481 / 3482 / 3483 |
23+
| `python-multipart` | `>=0.0.12`**`>=0.0.31`** | PYSEC-2026-3036 / 3037 / 3040 |
24+
| `pydantic-settings` | `>=2.6`**`>=2.14.2`** | GHSA-4xgf-cpjx-pc3j |
25+
26+
これらの古い版に固定している利用者は解決に失敗します。**その構成は脆弱**なので、
27+
更新してください。`uv.lock` はこのリポジトリの CI と開発環境しか守らないため、
28+
利用者へ伝播させるには宣言側の下限を上げる必要がありました。
29+
30+
### Added
31+
- `[tool.uv] constraint-dependencies = ["mcp<2"]` を追加し、mcp を **1.x 系に固定**した。
32+
- **何を止めているか**: `uv lock --upgrade` での mcp 2.0 系への意図しない追随。
33+
- **理由**: 2.0.0 で `mcp.server.fastmcp``mcp.server.mcpserver` へ改名され、
34+
`src/nene2/mcp/server.py``ModuleNotFoundError` で壊れる(実測済み)。
35+
advisory 要求の 1.28.1 は 1.x 系で完全に充足しており、急いで移行する必要がない。
36+
- **外す条件**: (a) 上流の mcp 1.x サポート終了、または (b) 2.0 固有機能が必要になったとき。
37+
- **参照**: 移行の設計ノートは [日報 2026-08-12 §2](docs/review/2026-08-12.md)
38+
- 🔑 `constraint-dependencies``uv.lock` の解決にのみ適用され、
39+
**`requires-dist` には漏れない**。実測で確認済み(`mcp``requires-dist`
40+
`>=1.28.1` のままで `<2` は含まれない)。したがって**利用者の解決に上限は伝播せず**
41+
ライブラリに上限を書いたときの下流での解決衝突を起こさない。
42+
43+
### Notes
44+
- 🔴 **`cryptography` / `starlette` / `pyjwt` は下限を上げていない**(本リリースの射程外)。
45+
実測の結果、これらは**親の下限では安全版に到達できない**ことが分かった:
46+
- `pyjwt``mcp[crypto]` の宣言は `pyjwt[crypto]>=2.10.1`(必要版 2.13.0 に届かない)
47+
- `cryptography``pyjwt[crypto]` の宣言は `cryptography>=3.4.0`(同上)
48+
- `starlette``fastapi 0.136.1`(最新)の宣言は `starlette>=0.46.0`(必要版 1.3.1 に届かない)
49+
50+
塞ぐには nene2-python が直接依存として宣言するしかなく、**使っていない依存を
51+
バージョン床のためだけに抱える**ことになる。ライブラリとしての是非を含めて要判断。
52+
- `msgpack``cachecontrol``pip-audit[filecache]` 経由の **dev 依存のみ**で、
53+
配布物には含まれない。利用者には影響しない。
1254

1355
CI を push から切り離し、週次で外界の変化(上流 advisory)を検知できるようにした。
1456

docs/review/2026-08-12.md

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# 日報 — 2026-08-12
22

33
**作業者**: hideyukiMORI
4-
**バージョン**: v1.8.169(セッション終了時点)
4+
**バージョン**: v1.8.170(セッション終了時点)
55

66
---
77

@@ -269,13 +269,69 @@ GitHub により自動的に無効化される**(公式ドキュメントに
269269

270270
---
271271

272-
## 5. 明日以降の方針
272+
## 5. 依存の下限引き上げと mcp の 1.x 固定(v1.8.170)
273+
274+
`uv.lock`**このリポジトリの CI と開発環境しか守らない**。PyPI から入れた利用者が
275+
古い版に固定していれば、脆弱な依存で動く。利用者へ伝播させるには宣言側を上げる必要がある。
276+
277+
### 5-1. 直接依存の下限をセキュリティ床として引き上げ(公開メタデータが変わる)
278+
279+
| 依存 | 変更 | advisory |
280+
|---|---|---|
281+
| `mcp` | `>=1.0`**`>=1.28.1`** | PYSEC-2026-3481 / 3482 / 3483 |
282+
| `python-multipart` | `>=0.0.12`**`>=0.0.31`** | PYSEC-2026-3036 / 3037 / 3040 |
283+
| `pydantic-settings` | `>=2.6`**`>=2.14.2`** | GHSA-4xgf-cpjx-pc3j |
284+
285+
### 5-2. mcp を 1.x 系に固定(`constraint-dependencies`
286+
287+
```toml
288+
[tool.uv]
289+
constraint-dependencies = ["mcp<2"]
290+
```
291+
292+
`pyproject.toml``dependencies``mcp<2` と書くと、**上限が全利用者へ伝播して
293+
下流の解決衝突を生む**(ライブラリに上限を書かない慣行の理由)。
294+
`constraint-dependencies``uv.lock` の解決にのみ適用され、`requires-dist` には漏れないので、
295+
**その副作用だけを外せる**。実測で確認した:
296+
297+
| 確認項目 | 結果 |
298+
|---|---|
299+
| 解決される `mcp` | **1.29.0**(2.0.0 へ飛ばない) |
300+
| `requires-dist``mcp` | **`>=1.28.1`**`<2` は含まれない) |
301+
| 対照: `uv lock --upgrade-package mcp` を明示実行 | **1.29.0 のまま・lock に差分なし** |
302+
303+
外す条件は (a) 上流の 1.x サポート終了、(b) 2.0 固有機能が必要になったとき。
304+
`pyproject.toml` のコメントに①何を止めているか②理由③外す条件④参照先を併記した。
305+
**理由の無い制約は、半年後には理由不明の呪いになる。**
306+
307+
### 5-3. 🔴 残り 4 パッケージは親の下限では塞げない(実測)
308+
309+
今回の advisory 8 パッケージのうち、直接依存は上記 3 つだけ。残り 4 つの経路を `uv tree` で実測:
310+
311+
| パッケージ | 経路 | 親の宣言 | 必要版 | 到達可否 |
312+
|---|---|---|---|---|
313+
| `pyjwt` |`mcp[crypto]` | `pyjwt[crypto]>=2.10.1` | 2.13.0 | 🔴 **不能** |
314+
| `cryptography` |`pyjwt[crypto]``mcp[crypto]` | `cryptography>=3.4.0` | 50.0.0 | 🔴 **不能** |
315+
| `starlette` |`fastapi``mcp``sse-starlette` | `fastapi 0.136.1`(最新)が `starlette>=0.46.0` | 1.3.1 | 🔴 **不能** |
316+
| `msgpack` |`cachecontrol``pip-audit[filecache]` | `msgpack>=0.5.2,<2.0.0` | 1.2.1 | 🟢 **dev 依存のみ・配布物に含まれない** |
317+
318+
**`msgpack` は利用者に無関係**(dev 専用)。残り 3 つは、**最新の親でさえ下限が足りない**ため、
319+
親の版を上げるという手段では到達できない。塞ぐには nene2-python が
320+
`pyjwt` / `cryptography` / `starlette`**直接依存として宣言する**しかなく、
321+
**使っていない依存をバージョン床のためだけに抱える**ことになる。
322+
323+
ライブラリとしての是非を含めて要判断のため、本リリースの射程外とした。
324+
325+
---
326+
327+
## 6. 明日以降の方針
273328

274329
| 優先度 | タスク |
275330
|---|---|
276-
|| **mcp 2.0 移行**(本日の調査 §2 が設計ノート。バージョン境界の決定が着手条件) |
277-
|| **依存の定期再検査を仕組み化**`schedule:` トリガー CI か月次 `uv lock --upgrade` 運用) |
278-
| 判断待ち | `pyproject.toml``mcp` / `python-multipart` / `pydantic-settings` の下限引き上げ(利用者影響あり) |
331+
| 判断待ち | 🔴 **推移的依存(`pyjwt` / `cryptography` / `starlette`)を直接宣言して床を作るか**(§5-3)。ライブラリが使っていない依存を抱える是非 |
332+
| 判断待ち | **CI 失敗の通知経路**(配信は機能しているが受信箱が飽和・§4) |
333+
|| 🔴 **週次 schedule 自体の生存監視**(60 日自動無効化・§4) |
334+
| 塩漬け | **mcp 2.0 移行**(§2 が設計ノート。`constraint` で 1.x 固定済み。解除条件は §5-2) |
279335
|| PyJWT 推移的 CVE(PYSEC-2025-183)— mcp 修正待ち |
280336

281337
オープン Issue / PR: ゼロ。main クリーン。**CI グリーン**(3.12 / 3.14・実 DB 統合テスト含む)。

docs/todo/current.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# TODO — current
22

33
最終更新: 2026-08-12
4-
現状: **v1.8.169 / 依存の既知脆弱性 22 件を解消し CI を緑に復帰 / 471 tests・カバレッジ 93%**
4+
現状: **v1.8.170 / 依存の既知脆弱性 22 件を解消し CI を緑に復帰 / 471 tests・カバレッジ 93%**
55

66
---
77

@@ -21,6 +21,16 @@
2121
- Python **3.12 / 3.14 の両方**で pytest・mypy・ruff・pip-audit を確認
2222
- 再発の根: **定期再検査の装置が無い**こと。コード凍結中でも advisory は増える
2323

24+
**2026-08-12(v1.8.170)— 依存の下限引き上げと mcp の 1.x 固定。**
25+
`uv.lock` はこのリポの CI と開発環境しか守らないため、利用者へ伝播させるべく宣言側を上げた。
26+
27+
- ⚠️ **公開メタデータ(`requires-dist`)が変わる**: `mcp>=1.28.1` / `python-multipart>=0.0.31` /
28+
`pydantic-settings>=2.14.2`。これより古い版に固定している利用者は解決に失敗する(その構成は脆弱)
29+
- `[tool.uv] constraint-dependencies = ["mcp<2"]` で mcp を **1.x 系に固定**
30+
`requires-dist` には漏れないため**利用者の解決に上限は伝播しない**(実測確認済み)
31+
- 🔴 `pyjwt` / `cryptography` / `starlette`**親の下限では塞げない**ことが実測で判明
32+
(下記「明日以降の優先タスク」の判断待ち行)
33+
2434
**2026-08-12(v1.8.168)— 記録の整備。**
2535
上記セッションの実測を [日報 2026-08-12](../review/2026-08-12.md) に記録した。
2636
とくに **§2 は mcp 2.0 移行の設計ノート**(依存の実体・2.0 での変更点・落ちた 4 本が
@@ -181,7 +191,8 @@ v1.8.161)、#553(#578 で実装済みを確認し close)、ハウスキー
181191
||| FT は保守 + オンデマンド(4 トリガー時のみ。[方法論](../explanation/field-trial-methodology.md)| FT |
182192
||| リリース時は `v*` タグ push → publish.yml が自動公開([手順](../how-to/release-and-publish.md)| infra |
183193
||| PyJWT 推移的 CVE(PYSEC-2025-183)— mcp 修正待ち | 保留 |
184-
||| **mcp 2.0 系への移行**(2026-08-12 調査済み)— 2.0.0 で `mcp.server.fastmcp``mcp.server.mcpserver` に改名。**実測の移行規模は概算 11 行**`src/nene2/mcp/server.py` の 1 行が唯一の依存点・`src/example/mcp.py``LocalMcpServer` 越しで変更不要)。実質的な破壊点は `call_tool()` の戻り値が `CallToolResult` になったことのみ。**着手条件=`mcp` のバージョン境界の決定**。調査と移行方針は [日報 2026-08-12 §2](../review/2026-08-12.md) が設計ノート。<br>🔴 **訂正**: 当初「`src/nene2/mcp/``src/example/mcp.py` の全面書き換えが必要」と記載していたが**過大評価だった**。根拠が「テストが 4 本落ちた」だけで依存の実体を測っていなかった(`grep``server.py` の 1 行のみと判明)。着手判断には訂正後の数字を使うこと | 保守 |
194+
| 🧊 塩漬け | — | **mcp 2.0 系への移行**(2026-08-12 調査済み・**v1.8.170 で 1.x 固定**)— 2.0.0 で `mcp.server.fastmcp` が `mcp.server.mcpserver` に改名。**実測の移行規模は概算 11 行**(`src/nene2/mcp/server.py` の 1 行が唯一の依存点・`src/example/mcp.py` は `LocalMcpServer` 越しで変更不要)。実質的な破壊点は `call_tool()` の戻り値が `CallToolResult` になったことのみ。`[tool.uv] constraint-dependencies = ["mcp<2"]` で固定済みなので**急がない**(advisory は 1.29.0 で全て閉じている)。**解除条件=(a) 上流の 1.x サポート終了 (b) 2.0 固有機能が必要になったとき**。調査と移行方針は [日報 2026-08-12 §2](../review/2026-08-12.md) が設計ノートで、**解除時にそのまま着手できる状態で凍結**してある。<br>🔴 **訂正**: 当初「`src/nene2/mcp/` と `src/example/mcp.py` の全面書き換えが必要」と記載していたが**過大評価だった**。根拠が「テストが 4 本落ちた」だけで依存の実体を測っていなかった(`grep` で `server.py` の 1 行のみと判明)。着手判断には訂正後の数字を使うこと | 保守 |
195+
| 判断待ち || 🔴 **推移的依存に床を作るか**(2026-08-12 実測)— `pyjwt` / `cryptography` / `starlette`**最新の親でさえ下限が足りず**、親の版を上げる手段では安全版に到達できない(`fastapi 0.136.1` の宣言は `starlette>=0.46.0`・必要版 1.3.1/`mcp 1.29.0` の宣言は `pyjwt[crypto]>=2.10.1`・必要版 2.13.0)。塞ぐには**使っていない依存を床のためだけに直接宣言する**しかない。ライブラリとしての是非を含めて要判断。[日報 2026-08-12 §5-3](../review/2026-08-12.md) | 判断 |
185196
| ~~~~ || ~~**依存の定期再検査を仕組み化**~~ | infra |
186197
|||**2026-08-12 解消(v1.8.169)**`ci.yml` に週次 `schedule`(月曜 09:30 JST)+ `workflow_dispatch``concurrency``github.event_name` 込み)を追加。[日報 2026-08-12 §4](../review/2026-08-12.md) | infra |
187198
||| 🔴 **週次 schedule 自体の生存監視**(2026-08-12 判明)— public リポの scheduled workflow は**活動が 60 日無いと GitHub が自動無効化**する。本リポの空白は **74 日**で 14 日超過しており、**装置が自身の検知対象によって止められうる**。外部からの `workflow_dispatch` 発火など、リポジトリ単体では解決できない | infra |

pyproject.toml

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "nene2-python"
3-
version = "1.8.169"
3+
version = "1.8.170"
44
description = "NENE2 Python — minimal API framework following NENE2's design philosophy"
55
readme = "README.md"
66
license = {text = "MIT"}
@@ -25,12 +25,15 @@ dependencies = [
2525
"fastapi>=0.115",
2626
"uvicorn[standard]>=0.32",
2727
"pydantic>=2.9",
28-
"pydantic-settings>=2.6",
29-
"python-multipart>=0.0.12",
28+
# 下限はセキュリティ床でもある。以下 3 つは 2026-08-12 に既知脆弱性が確認された版を
29+
# 利用者が選べないようにするための引き上げ(uv.lock はこのリポの CI と開発環境しか
30+
# 守らないため、利用者へ伝播させるには宣言側を上げる必要がある)。
31+
"pydantic-settings>=2.14.2", # GHSA-4xgf-cpjx-pc3j
32+
"python-multipart>=0.0.31", # PYSEC-2026-3036 / 3037 / 3040
3033
"sqlalchemy>=2.0.49",
3134
"alembic>=1.18.4",
3235
"structlog>=24.0",
33-
"mcp>=1.0",
36+
"mcp>=1.28.1", # PYSEC-2026-3481 / 3482 / 3483(上限は [tool.uv] の constraint 側で管理)
3437
"pyyaml>=6.0",
3538
"httpx>=0.27",
3639
]
@@ -65,6 +68,27 @@ dev = [
6568
"pymysql>=1.1",
6669
]
6770

71+
# ---------------------------------------------------------------------------
72+
# uv — ローカル/CI の解決だけに効く制約
73+
#
74+
# constraint-dependencies は uv.lock の解決に適用されるが、配布物の依存要件
75+
# ([package.metadata] requires-dist)には漏れない。つまり利用者の解決には
76+
# 影響しないので、ライブラリに上限を書く際の副作用(下流の解決衝突)を伴わない。
77+
# ---------------------------------------------------------------------------
78+
[tool.uv]
79+
constraint-dependencies = [
80+
# ① 何を止めているか: mcp 2.0 系への自動追随(`uv lock --upgrade` での意図しない飛び)。
81+
# ② 理由: 2.0.0 で `mcp.server.fastmcp` が `mcp.server.mcpserver` へ改名され、
82+
# `src/nene2/mcp/server.py` の `from mcp.server.fastmcp import FastMCP` が
83+
# ModuleNotFoundError で壊れる(2026-08-12 に実測。MCP 系テスト 4 本が収集エラー)。
84+
# 現行の advisory 要求は 1.28.1 以上であり、1.x 系で完全に充足している。
85+
# ③ 外す条件: (a) 上流の mcp 1.x サポートが終了したとき、または
86+
# (b) 2.0 固有の機能が必要になったとき。どちらかが満たされたら外して移行する。
87+
# ④ 参照: 移行の設計ノート(実測の移行規模・方針 4 案と推し・再現手順)は
88+
# docs/review/2026-08-12.md §2。解除時はそのまま着手できる状態で凍結してある。
89+
"mcp<2",
90+
]
91+
6892
# ---------------------------------------------------------------------------
6993
# pytest
7094
# ---------------------------------------------------------------------------

uv.lock

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)