diff --git a/.github/ISSUE_TEMPLATE/quality.md b/.github/ISSUE_TEMPLATE/quality.md index d6ce2e73d..ef0a76c47 100644 --- a/.github/ISSUE_TEMPLATE/quality.md +++ b/.github/ISSUE_TEMPLATE/quality.md @@ -36,7 +36,7 @@ labels: quality improvement .\2_RunAllTests.ps1 .\3_SmokeTest.ps1 -合格の目安は 全ステップ OK / 8-8 差分 0 / 25-25。 +合格の目安は 全ステップ OK / 8-8 差分 0 / 29-29。 --> ## 利用者への影響 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fdeff7416..93bd39f6c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -25,7 +25,7 @@ .\2_RunAllTests.ps1 .\3_SmokeTest.ps1 -合格の目安は 全ステップ OK / 8-8 差分 0 / 25-25。 +合格の目安は 全ステップ OK / 8-8 差分 0 / 29-29。 文書だけの変更なら「不要」と書いてください。 --> diff --git a/AGENTS.md b/AGENTS.md index 232dff858..3206a8af8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -180,105 +180,41 @@ Copyright ブロックの扱い、`ArgumentException` 系の引数の順、`.bat | 単体テストの実行と判定 | [`TESTING.md`](root/programs/TESTING.md) | | サンプルの疎通確認 | [`SMOKETEST.md`](root/programs/SMOKETEST.md) | -検証は次の 3 本で、いずれも終了コードで合否が分かる。**この順で実行すること。** +検証は `1_BuildAll.ps1`(ビルド)→ `2_RunAllTests.ps1`(単体テスト)→ +`3_SmokeTest.ps1`(疎通)の 3 本で、いずれも終了コードで合否が分かる。 +**順序は固定**(1 のクリーンとアセンブリ配置が 2・3 の前提)。 -```powershell -cd root\programs -.\1_BuildAll.ps1 # 全ビルド -.\2_RunAllTests.ps1 # 単体テスト -.\3_SmokeTest.ps1 # サンプルの疎通 -``` +**本書にコマンドは書かない。** 引数(`-IgnoreErrors` / `-Only` / `-List` / `-Lang`)と +合格の目安は [`CHEATSHEET.md`](root/programs/CHEATSHEET.md) 1 節が一次情報である。 +**転記すると、両方を直さないかぎりズレる。** `2_RunAllTests.ps1` はワーキング ツリーの `Result*.txt` を書き換える(従来のバッチ運用と同じ)。 **コミットの要否は人が判断する**ため、エージェントは差分を報告するに留める。 +**`-Only` で絞れば、書き換わるのも絞った分だけになる。** -**エージェントは、この 3 本を個別に実行することを検討する。**(#576) -`0_RunAll.ps1` は 3 本をまとめて回す**利用者向けの入口**であり、 -**必要な 1 本だけを選ぶ、という判断が入らない。** -どれを回すかは、次節の対応表で決める。 - -```powershell -.\1_BuildAll.ps1 -Only "Framework_Tool" # ビルドするものだけ -.\2_RunAllTests.ps1 -Only "TestBatch" # テスト結果 Result*.txt が絞られる -.\3_SmokeTest.ps1 -Only "DeployZip" # 確かめるものだけ -``` - -**`-Only` に何を指定できるかは `-List` で出す。** -**文書には一覧を書かない。** 対象が増減したときに古くなるため、 -スクリプト自身を一次情報にする(ツールの `/HELP` と同じ考え方)。 - -```powershell -.\1_BuildAll.ps1 -List -Lang Both # 45 ステップ -.\2_RunAllTests.ps1 -List # 8 件 -.\3_SmokeTest.ps1 -List -Lang VB # 6 件(-Lang が効く) -``` - -**3 本とも `-Only` が空振りしたら終了コード 1 で止まる。** -打ち間違いが「全ステップ OK」になることはない。 - -#### 通しで回す前に、依存関係を見る(#576) +#### 回す範囲は、依存関係で決める(#576) **全部回すのは「安全」ではない。遅いだけのことがある。** -依存の向きは一方向で、段は 2 つしかない。 - -``` -基盤 NuGet / Business / Business.RichClient / CopyAssemblies - ↓ (ここが変われば、下は全部やり直し) -末端 Tools / 各サンプル / Tests -``` - -**ツールと個別サンプルは末端である。** そこを変えても、基盤も他のサンプルも変わらない。 - -| 変更した場所 | `1_BuildAll` | `2_RunAllTests` | `3_SmokeTest` | -|---|---|---|---| -| `Infrastructure/`(基盤) | **通し** | **通し** | **通し** | -| `Tools/`(ツール) | `-Only Framework_Tool` | **不要** | `-Only <そのツール>` | -| 個別サンプル | `-Only <サンプル>` | **不要** | `-Only <サンプル>` | -| `Tests/` | `-Only <対象>` | `-Only <対象>` | **不要** | -| `.ps1` / `.md` のみ | **不要** | **不要** | **不要** | - -**`2_RunAllTests.ps1` の対象はフレームワークのテストだけ**である。 -`Tools/` や個別サンプルを変えても、ここは動かない。回す理由が無い。 - -実測(`0_RunAll.ps1 -Lang Both` は 24.6 分)。 - -``` -基盤のビルド 122.8 秒 -Framework_Tool 系だけ 74.8 秒 ← ツールの変更で必要なのはこちら -2_RunAllTests 通し 111.6 秒 -2_RunAllTests -Only 35 秒ほど -``` - -**ツールだけの変更なら、1/16 ほどで終わる。** - -#### 時間だけの問題ではない +`0_RunAll.ps1` は 3 本をまとめて回す**利用者向けの入口**であり、 +**必要な 1 本だけを選ぶ、という判断が入らない。** +エージェントは**3 本を個別に実行することを検討する。** -`2_RunAllTests.ps1` は**ワーキング ツリーの `Result*.txt` を書き換える。** -関係の無い対象まで回すと、**人が確認してコミットする差分が増える。** +ツールと個別サンプルは**依存の末端**で、そこを変えても基盤も他のサンプルも変わらない。 +`2_RunAllTests.ps1` の対象は**フレームワークのテストだけ**で、 +ツールやサンプルを変えても動かない。**回す理由が無い。** -`-Only` で絞れば、書き換わるのは絞った対象の分だけになる。 +**どこまで回すかは [`CHEATSHEET.md`](root/programs/CHEATSHEET.md) 1 節の対応表で決める。** -#### それでも通しを回す場面 +通しを回すのは次の場合。 - **基盤(`Infrastructure/`)に触れたとき** -- **リリース前**(`RELEASE.md`) -- **絞り込みで妙なエラーが出たとき**(再現するかを見る) - -3 本目は制約による誤検知が実際にある。 -`-Only` は前段が用意した状態に依存するステップを落とすことがあり、 -**変更と無関係なエラーに見える。** 詳細は -[`CHEATSHEET.md`](root/programs/CHEATSHEET.md) 1 節の -「`-Only` + `-SkipClean` は万能ではない」。 +- **リリース前**([`RELEASE.md`](root/programs/RELEASE.md)) +- **絞り込みで妙なエラーが出たとき**(再現するかを見る。制約による誤検知が実際にある) **判断に迷ったら通しでよい。** ただし**迷っていないのに通すのは、ただの浪費である。** **上記の既定は C# 側である。VB 側に手を入れたときは `-Lang` で回す。** - -```powershell -.\0_RunAll.ps1 -Lang VB # 1 と 3 を VB で通す(2 は VB に対象が無い) -``` - 理由と対象は [`BUILDING.md`](root/programs/BUILDING.md) 10 節・ [`SMOKETEST.md`](root/programs/SMOKETEST.md) 10 節。 diff --git a/root/programs/BUILDING.md b/root/programs/BUILDING.md index 5d0c8ce48..1282f679a 100644 --- a/root/programs/BUILDING.md +++ b/root/programs/BUILDING.md @@ -738,7 +738,7 @@ VS 18 のある環境では従来どおり `18.0` になるため、**挙動は ### 実測(run 30984111639 : 全ステップ成功) > **当時の件数での記録。** その後、単体テストは 8 ケース(#520)、 -> 疎通は 25 件(#528、#546、#566、#570、#571)である。**時間の目安として読むこと。** +> 疎通は 29 件(#528、#546、#566、#570、#571、#578)である。**時間の目安として読むこと。** ### 警告の内訳を見る(`-WarnDetail`、#571) diff --git a/root/programs/CHEATSHEET.md b/root/programs/CHEATSHEET.md index 6299a8225..b76f9fe55 100644 --- a/root/programs/CHEATSHEET.md +++ b/root/programs/CHEATSHEET.md @@ -26,7 +26,7 @@ cd root\programs |---|---|---| | ビルド | 全ステップ OK | [`BUILDING.md`](BUILDING.md) | | 単体テスト | 8/8 OK、差分 0 | [`TESTING.md`](TESTING.md) | -| 疎通 | 25/25 OK | [`SMOKETEST.md`](SMOKETEST.md) | +| 疎通 | 29/29 OK | [`SMOKETEST.md`](SMOKETEST.md) | **既定は C# 側。VB 側は `-Lang` で回す**(3 節)。 @@ -41,14 +41,16 @@ cd root\programs ### 通しは長い。反復では絞り込む(#571) -実測(`-Lang Both`)は **合計 21.7 分**で、内訳はこうなっている。 +実測(`-Lang Both`)は **合計 24.6 分**で、内訳はこうなっている。 ``` -1_BuildAll.ps1 12.6 分 ← 58%。ここが主因 -2_RunAllTests.ps1 1.7 分 -3_SmokeTest.ps1 7.4 分 +1_BuildAll.ps1 15.5 分 ← 63%。ここが主因 +2_RunAllTests.ps1 1.9 分 +3_SmokeTest.ps1 7.3 分 ``` +**環境と状態で振れる。** 桁を掴むための目安として見ること。 + **変更した箇所だけを回す。** 通しは最後に 1 回でよい。 ```powershell @@ -64,10 +66,36 @@ cd root\programs ``` **どこまで回すかは依存関係で決まる。**(#576) -ツールと個別サンプルは末端なので、基盤のビルドも他のサンプルの疎通も要らない。 + +依存の向きは一方向で、段は 2 つしかない。 + +``` +基盤 NuGet / Business / Business.RichClient / CopyAssemblies + ↓ (ここが変われば、下は全部やり直し) +末端 Tools / 各サンプル / Tests +``` + +| 変更した場所 | `1_BuildAll` | `2_RunAllTests` | `3_SmokeTest` | +|---|---|---|---| +| `Infrastructure/`(基盤) | **通し** | **通し** | **通し** | +| `Tools/`(ツール) | `-Only Framework_Tool` | **不要** | `-Only <そのツール>` | +| 個別サンプル | `-Only <サンプル>` | **不要** | `-Only <サンプル>` | +| `Tests/` | `-Only <対象>` | `-Only <対象>` | **不要** | +| `.ps1` / `.md` のみ | **不要** | **不要** | **不要** | + **`2_RunAllTests.ps1` の対象はフレームワークのテストだけ**で、 -ツールやサンプルを変えても動かないため、回す理由が無い。 -対応表は [`AGENTS.md`](../../AGENTS.md)「通しで回す前に、依存関係を見る」。 +ツールやサンプルを変えても動かない。**回す理由が無い。** + +**ツールだけの変更なら、通しの 1/16 ほどで終わる。** + +``` +基盤のビルド 122.8 秒 +Framework_Tool 系だけ 74.8 秒 ← ツールの変更で必要なのはこちら +2_RunAllTests 通し 111.6 秒 +2_RunAllTests -Only 35 秒ほど +``` + +**通しを回す場面の判断は [`AGENTS.md`](../../AGENTS.md)「回す範囲は、依存関係で決める」。** **警告が多いステップの内訳を見る。** diff --git a/root/programs/CS/Frameworks/Infrastructure/Business/Presentation/MyMVCCoreFilterAttribute.cs b/root/programs/CS/Frameworks/Infrastructure/Business/Presentation/MyMVCCoreFilterAttribute.cs index 6444ee94f..57a909e23 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Business/Presentation/MyMVCCoreFilterAttribute.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Business/Presentation/MyMVCCoreFilterAttribute.cs @@ -28,7 +28,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2018/08/08 西野 大介 新規作成 -//* 2026/08/21 玄人 幸道 CS4014対応(GetUserInfoAsyncを待つ。ログのUserInfoが空になっていた) +//* 2026/08/21 玄人 幸道 CS4014対応(GetUserInfoAsyncを待つ。ログのUserInfoが空になっていた)(#575) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Util/FxLiteral.cs b/root/programs/CS/Frameworks/Infrastructure/Framework/Util/FxLiteral.cs index 269a926f4..871cea1dd 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Util/FxLiteral.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Util/FxLiteral.cs @@ -56,6 +56,7 @@ //* 2014/10/03 Rituparna Added constants for RadioButtonList,CheckBoxList events and prefix. //* 2015/04/16 Supragyan Added constants for Textbox events and prefix. //* 2017/08/28 西野 大介 非同期メソッドのリテラルを追加した。 +//* 2026/08/14 玄人 幸道 ConnectionGroupNameが現在は効果を持たない旨をremarksに明記(#546) //********************************************************************************** namespace Touryo.Infrastructure.Framework.Util diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/UnZipperV2.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/UnZipperV2.cs index 53ff5f978..b2ed70efe 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/IO/UnZipperV2.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/UnZipperV2.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2026/08/08 玄人 幸道 新規作成(#524) +//* 2026/08/08 玄人 幸道 解凍したファイルのパスを保持するExtractedFilesを追加(#528) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipBaseV2.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipBaseV2.cs index c2d6b2743..1463d85f2 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipBaseV2.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipBaseV2.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2026/08/08 玄人 幸道 新規作成(#524) +//* 2026/08/08 玄人 幸道 ZippedFiles・ExtractedFilesの追加に伴う共通部の調整(#528) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipEnumV2.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipEnumV2.cs index cf93cd99a..5e82dc34e 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipEnumV2.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipEnumV2.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2026/08/08 玄人 幸道 新規作成(#524) +//* 2026/08/08 玄人 幸道 ZippedFiles・ExtractedFilesの追加に伴う定義の調整(#528) //********************************************************************************** namespace Touryo.Infrastructure.Public.IO diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipperV2.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipperV2.cs index 2a40f08a9..c19109b49 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipperV2.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipperV2.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2026/08/08 玄人 幸道 新規作成(#524) +//* 2026/08/08 玄人 幸道 圧縮したファイルのパスを保持するZippedFilesを追加(#528) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Jwt/EccPublicKeyConverter.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Jwt/EccPublicKeyConverter.cs index 9d920ceb1..c2fd8f569 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Jwt/EccPublicKeyConverter.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Jwt/EccPublicKeyConverter.cs @@ -34,7 +34,7 @@ //* 2019/06/25 西野 大介 インスタンス・メソッド化(ES256, 384, 512対応) //* 2026/08/01 玄人 幸道 jose-jwtへの依存を解消(JwkToCngをBCLのみで実装) //* ※ 楕円曲線の決定にcrvを使用するため、jose-jwt非互換。 -//* 2026/08/21 玄人 幸道 CA1416対応(JwkToCngにSupportedOSPlatformを付与) +//* 2026/08/21 玄人 幸道 CA1416対応(JwkToCngにSupportedOSPlatformを付与)(#575) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tests/TestCode/Program.cs b/root/programs/CS/Frameworks/Tests/TestCode/Program.cs index 1008e51e6..f1fea76b9 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/Program.cs +++ b/root/programs/CS/Frameworks/Tests/TestCode/Program.cs @@ -26,6 +26,7 @@ //* 2019/02/06 西野 大介 新規作成 //* 2026/08/18 玄人 幸道 各テストを個別に try で囲むようにした(#564)。 //* 1 つが例外を投げると、以降が実行されなかった。 +//* 2026/08/08 玄人 幸道 TestZipV2の呼び出しを追加(#524) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestDto.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestDto.cs index b2b770565..920ea19f8 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/TestDto.cs +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestDto.cs @@ -25,6 +25,8 @@ //* ---------- ---------------- ------------------------------------------------- //* 2026/08/06 玄人 幸道 新規作成(#522) //* 2026/08/14 玄人 幸道 JSONの往復と、行ステータスの往復を追加(#544) +//* 2026/08/18 玄人 幸道 keepOriginalとバッチ更新の使い方のテストを追加(#567) +//* 2026/08/17 玄人 幸道 DTTablesの中間形式のテストを追加(#552) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestOutputLog.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestOutputLog.cs index 6c0b66d03..6aec5bce8 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/TestOutputLog.cs +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestOutputLog.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2020/07/31 西野 大介 新規作成 +//* 2026/08/17 玄人 幸道 ログレベルの有効・無効(IsDebugEnabledほか)のテストを追加(#552) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestResourceLoader.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestResourceLoader.cs index aeb226e15..7d8482f73 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/TestResourceLoader.cs +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestResourceLoader.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2026/08/06 玄人 幸道 新規作成(#522) +//* 2026/08/17 玄人 幸道 LoadAsStreamのテストを追加(#552) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestUtil.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestUtil.cs index 094a08eac..76240a95d 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/TestUtil.cs +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestUtil.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2026/08/06 玄人 幸道 新規作成(#522) +//* 2026/08/17 玄人 幸道 設定取得・環境変数展開・コマンド引数のテストを追加(#552) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestXmlLib.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestXmlLib.cs index 04c14c4c2..1d47bd348 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/TestXmlLib.cs +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestXmlLib.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2019/05/30 西野 大介 新規作成 +//* 2026/08/18 玄人 幸道 GetAttributeByTagNameのindex指定と範囲外の挙動のテストを追加(#563) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.cs index 03007b9be..797e2a063 100644 --- a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.cs +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.cs @@ -46,6 +46,7 @@ //* 2020/08/03 西野 大介 NETCOREAPP対応 //* 2026/08/01 玄人 幸道 ZIP部品をV2へ差し替え(#524)。 //* CUI化のためマニフェスト生成と圧縮をstaticメソッドへ抽出(#528) +//* 2026/08/11 玄人 幸道 文言の直書きをやめ、Resource.resxとResourceMgrへ移した(#528) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.cs index 62d3d71e4..23e846cbe 100644 --- a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.cs +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.cs @@ -45,6 +45,8 @@ //* 2011/09/12 西野 大介 画面表示せず、ログ出力のみする例外処理方式を追加 //* 2014/04/26 Sai Replaced all the Japanese language in both UI and code with ResorceManager.GetString() method call //* 2020/08/03 西野 大介 NETCOREAPP対応 +//* 2026/08/08 玄人 幸道 ZippedFiles・ExtractedFilesの利用に合わせた調整(#528) +//* 2026/08/21 玄人 幸道 SYSLIB0003対応(CASを#if !NETCOREAPPで囲む。net48では生きているため)(#575) //********************************************************************************** using System; diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Program.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Program.cs index 81c42c785..5cb78e573 100644 --- a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Program.cs +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Program.cs @@ -63,6 +63,7 @@ //* 2016/01/07 Sandeep Comment out the DefaultWebProxy property, because there is no use of this property in the component //* 2026/08/01 玄人 幸道 CUI化(/MFTGEN, /ZIPGEN, /TOPONLY)と、引数不正時のGUI起動抑止(#528)。 //* 設定・履歴の保存をBinarySerializeからJSONへ変更 +//* 2026/08/21 玄人 幸道 SYSLIB0021/0014対応(MD5.CreateとHttpClientへ移行)(#575) //********************************************************************************** using System; diff --git a/root/programs/CS/Samples4NetCore/Backend/ASPNETWebService/ASPNETWebService/Controllers/BatchUpdateController.cs b/root/programs/CS/Samples4NetCore/Backend/ASPNETWebService/ASPNETWebService/Controllers/BatchUpdateController.cs index f3ff95c09..a4c9c04ac 100644 --- a/root/programs/CS/Samples4NetCore/Backend/ASPNETWebService/ASPNETWebService/Controllers/BatchUpdateController.cs +++ b/root/programs/CS/Samples4NetCore/Backend/ASPNETWebService/ASPNETWebService/Controllers/BatchUpdateController.cs @@ -24,6 +24,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2026/08/20 玄人 幸道 新規作成(#570) +//* 2026/08/21 玄人 幸道 CSRFが成立しない前提をコメントに明記(CodeQL誤検知) //********************************************************************************** using System; @@ -56,6 +57,16 @@ namespace ASPNETWebService.Controllers /// 更新 : JSON → DTTables → ToDataTable() → RowState と Original が戻った DataTable /// /// **keepOriginal を立てないと、楽観排他が組めない。**(#567) + /// + /// **OAuth2 の Resource Server であり、CSRF は成立しない。** + /// Cookie 認証を使わず(Startup.cs で UseAuthentication を無効化)、 + /// 認証は Authorization: Bearer ヘッダ。**ブラウザは自動付与しない。** + /// CORS も AllowCredentials を外してあり、資格情報を送らない構成。 + /// + /// **ValidateAntiForgeryToken は付けないこと。** + /// 非ブラウザのクライアント(Frameworks/Tests/TestWebAPIClient)は + /// トークンを持たないため、付けると疎通が壊れる。 + /// CodeQL の cs/web/missing-token-validation は false positive として dismiss 済み。 /// [EnableCors] [ApiController] diff --git a/root/programs/CS/Samples4NetCore/Backend/ASPNETWebService/ASPNETWebService/Controllers/JsonController.cs b/root/programs/CS/Samples4NetCore/Backend/ASPNETWebService/ASPNETWebService/Controllers/JsonController.cs index 758531517..5133063e4 100644 --- a/root/programs/CS/Samples4NetCore/Backend/ASPNETWebService/ASPNETWebService/Controllers/JsonController.cs +++ b/root/programs/CS/Samples4NetCore/Backend/ASPNETWebService/ASPNETWebService/Controllers/JsonController.cs @@ -29,6 +29,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2017/08/18 西野 大介 新規作成 +//* 2026/08/21 玄人 幸道 CSRFが成立しない前提をコメントに明記(CodeQL誤検知) //********************************************************************************** using System; @@ -67,7 +68,17 @@ namespace ASPNETWebService.Controllers /// /// ASP.NET WebAPI JSON-RPCの個別Webメソッドを公開するサービス インターフェイス基盤。 /// - + /// + /// **OAuth2 の Resource Server であり、CSRF は成立しない。** + /// Cookie 認証を使わず(Startup.cs で UseAuthentication を無効化)、 + /// 認証は Authorization: Bearer ヘッダ。**ブラウザは自動付与しない。** + /// CORS も AllowCredentials を外してあり、資格情報を送らない構成。 + /// + /// **ValidateAntiForgeryToken は付けないこと。** + /// 非ブラウザのクライアント(Frameworks/Tests/TestWebAPIClient)は + /// トークンを持たないため、付けると疎通が壊れる。 + /// CodeQL の cs/web/missing-token-validation は false positive として dismiss 済み。 + /// [EnableCors] [ApiController] [MyBaseAsyncApiController(httpAuthHeader: diff --git a/root/programs/RELEASE.md b/root/programs/RELEASE.md index e84126bef..d8c2147fd 100644 --- a/root/programs/RELEASE.md +++ b/root/programs/RELEASE.md @@ -185,7 +185,7 @@ cd root\programs - [ ] **`1_BuildAll.ps1` のエラーが「既知の 1 件」だけである** … `-SkipClean` は**使わない**。前回の成果物が残っていると通ったように見える - [ ] **`2_RunAllTests.ps1` が終了コード 0**(8 ケース) -- [ ] **`3_SmokeTest.ps1` が終了コード 0**(25 件) +- [ ] **`3_SmokeTest.ps1` が終了コード 0**(29 件) > **`1_BuildAll.ps1` は現状ここで終了コード 1 になる。** > `WSClnt_sample (net48)` の ClickOnce 署名エラー(`MSB3482`)が残るため。 @@ -209,7 +209,7 @@ cd root\programs |---|---| | `1_BuildAll.ps1`(31 ステップ) | 5.8 分 | | `2_RunAllTests.ps1`(8 ケース) | 1.3 分 | -| `3_SmokeTest.ps1`(25 件) | 7.4 分 | +| `3_SmokeTest.ps1`(29 件) | 7.4 分 | ### VB 側は、この 3 本に含めない diff --git a/root/programs/SMOKETEST.md b/root/programs/SMOKETEST.md index 461dd118c..5db82ff6e 100644 --- a/root/programs/SMOKETEST.md +++ b/root/programs/SMOKETEST.md @@ -81,7 +81,7 @@ cd root\programs --- -## 3. 対象(25 件) +## 3. 対象(29 件) **基盤系を先に置く。**(#571) 環境やツールが壊れていれば、アプリケーションの検証を待たずに分かる。 @@ -144,7 +144,7 @@ NG : /OUTPUT "C:\temp\out" ← \ が消える **`3_SmokeTest.ps1` は `Start-Process` でファイルへ直接リダイレクトする。** パイプ(`\| Out-File`)でも出力自体は取れるが、そちらは別の問題を抱える(9 節)。 -### DeployZipPackWithHTTP の CUI モード(4 件) +### DeployZipPackWithHTTP の CUI モード(8 件) | 対象 | 判定 | |---|---| @@ -156,6 +156,52 @@ NG : /OUTPUT "C:\temp\out" ← \ が消える 前段の出力を後段の入力に使う点は `DaoGen_Tool` と同じ。 **配布物(ZIP)は追跡していない。** `Pre` で `FormAppRoot` から毎回作る。 +#### プロキシ経由も確かめる(#578) + +`#575` で `HttpWebRequest` を `HttpClient` へ移した際、 +**`HttpClientHandler` では `Proxy = null` が「使わない」にならない**(`UseProxy = false` が要る) +という差があった。実際に通して確かめる。 + +| 対象 | 判定 | +|---|---| +| `DeployZip 配置 プロキシ` (net48 / net10.0) | 配置が一致し、**プロキシのログに要求が並ぶ** | +| `DeployZip 配置 プロキシ認証` (net48 / net10.0) | 上記に加え、**`[407]` が記録される** | + +**配置の成功だけでは足りない。** プロキシを無視して直結しても成功するため、 +`Test-ProxyUsed` でログを見る。マニフェストと ZIP の両方が通っていることまで確認する。 + +プロキシは `st_Proxy.ps1`(`TcpListener` の最小実装)。 +`HttpListener` は使えない。**プロキシへの要求は要求行が絶対 URI** +(`GET http://host:port/path HTTP/1.1`)で来るため、 +プレフィクス登録で受ける `HttpListener` では扱えない。 + +##### 踏んだ落とし穴 + +**① `.NET Framework` は localhost 宛のプロキシを無条件にバイパスする。** + +``` +BypassProxyOnLocal(既定) False +IsBypassed(localhost) **True** ← 設定に関わらず +IsBypassed(example.com) False +``` + +配信が `localhost` にある限り net48 では経路を確かめられない。 +`hosts` は書き換えず、**別名(`deploy.smoketest`)を使い、 +プロキシ側で `localhost` に繋ぎ替える**(`-MapHost`)。 + +**② `Host` ヘッダも繋ぎ替える。** IIS Express は `Host` が `localhost` でない要求を受け付けない。 + +**③ 応答は長さに従って読む。** 「上流が閉じるまで読む」では**本体を持たない HEAD で止まる。** + +**④ 起動待ちは「ポートに繋がるか」では足りない。** +前回のプロキシが待ち受けを握ったままだと接続は成功し、 +新しいプロセスは死んでいるのに起動したと誤認する。**自分のログに `[start]` が出るまで待つ。** + +> **同じ理由で `Stop-DeployWeb` も直した。**(#578) +> 残った `iisexpress` は 51084 を握り続け、**前回の web フォルダを配り続ける。** +> 実測では net48 の配置が `deploy_core` のマニフェストを読み、 +> そちらへ展開していた。**配置は成功するため異常が出ず、判定だけが 0 件になる。** + ``` /ZIPGEN /TOPONLY → root.zip(ルート直下だけ、書庫内ルート無し) @@ -641,7 +687,7 @@ MVC_Sample (net10.0) OK ログイン後 /Crud1/Index = 200 全対象 OK ``` -全 25 件(ビルド 10 バッチ + 疎通 25 件)で **約 7.4 分**。 +全 29 件(ビルド 10 バッチ + 疎通 29 件)で **約 8 分**。 **#571 の統合で、13.9 分から半減した。** 同じ WebAPI を相手にしながらホストを 2 回起動していたのをやめたため。 @@ -669,9 +715,13 @@ MVC_Sample (net10.0) OK ログイン後 /Crud1/Index = 200 | `st_Server.ps1` | サーバー系(Web ホストの起動と停止、HTTP 要求) | | `st_Flow.ps1` | アプリケーション検証フロー(WebForms / MVC) | | `st_Targets.ps1` | テスト対象定義(CS / VB) | +| `st_Proxy.ps1` | プロキシ経由の確認に使う最小 HTTP プロキシ(#578) | **ドット ソースで読む。** `& file` では関数と変数が呼び出し元のスコープに入らない。 +**`st_Proxy.ps1` だけは別。** 独立したプロセスとして起動するため読み込まない +(`Start-Process` で待ち受けさせる)。 + ```powershell . (Join-Path $PSScriptRoot "st_Utility.ps1") . (Join-Path $PSScriptRoot "st_Server.ps1") @@ -773,7 +823,7 @@ $client.Connect("localhost", $port) ```powershell .\3_SmokeTest.ps1 -Lang VB # VB のみ(6 件) -.\3_SmokeTest.ps1 -Lang Both # C# 25 件 + VB 6 件 +.\3_SmokeTest.ps1 -Lang Both # C# 29 件 + VB 6 件 ``` **既定に VB を含めない。** リリース時の検証([`RELEASE.md`](RELEASE.md) 3 節)は diff --git a/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/App_Start/RouteConfig.vb b/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/App_Start/RouteConfig.vb index 0b139d39b..86650cac3 100644 --- a/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/App_Start/RouteConfig.vb +++ b/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/App_Start/RouteConfig.vb @@ -15,6 +15,7 @@ '* 日時 更新者 内容 '* ---------- ---------------- ------------------------------------------------- '* 20xx/xx/xx XX XX XXXX +'* 2026/08/16 玄人 幸道 FriendlyUrlsの例を参照ごと削除し、コメントを整理(#554) '********************************************************************************** Imports System.Web.Routing diff --git a/root/programs/st_Proxy.ps1 b/root/programs/st_Proxy.ps1 new file mode 100644 index 000000000..12539d3f5 --- /dev/null +++ b/root/programs/st_Proxy.ps1 @@ -0,0 +1,272 @@ +<# +.SYNOPSIS + 疎通テスト用の最小 HTTP プロキシ + +.DESCRIPTION + DeployZipPackWithHTTP の /ProxyURL 経路を確かめるために立てる(#578)。 + + **HttpListener は使えない。** プロキシへの要求は要求行が絶対 URI + (GET http://host:port/path HTTP/1.1)で来るため、 + プレフィクス登録で受ける HttpListener では扱えない。TcpListener で受ける。 + + **平文 HTTP だけを扱う。** CONNECT(HTTPS トンネル)は実装しない。 + 配布に使うのは平文であり、そこを確かめれば足りる。 + + -User を指定すると Basic 認証を要求する(407 を返す)。 + ProxyUID / ProxyPWD が WebProxy.Credentials に載るかを確かめるため。 + + **要求行をログに残す。** 配置が成功しただけでは、 + プロキシを無視して直結した場合と区別がつかない。 + ログに URL が並んで初めて「経路を通った」と言える。 + + **単体で起動する**(3_SmokeTest.ps1 から Start-Process で呼ばれる)。 + +.PARAMETER Port + 待ち受けるポート。 + +.PARAMETER LogPath + 要求行を書き出す先。 + +.PARAMETER User + 指定すると Basic 認証を要求する。省略時は素通し。 + +.PARAMETER Password + Basic 認証のパスワード。 + +.PARAMETER MapHost + この名前宛の要求を -MapTo へ繋ぎ替える。 + + **.NET Framework の WebProxy は localhost 宛を無条件にバイパスする** + (BypassProxyOnLocal = False でも IsBypassed が True)。 + 配信サーバが localhost にある限り、net48 ではプロキシを通らない。 + hosts を書き換えるのは環境を変えるので採らず、**プロキシ側で解決する。** + +.PARAMETER MapTo + -MapHost の繋ぎ替え先。既定は localhost。 + + **Host ヘッダも書き換える。** IIS Express は Host が localhost でない要求を + 受け付けないため、別名のまま渡すと 4xx になる。 + +.NOTES + 作成者 :玄人 幸道 + 更新履歴 : + 日時 更新者 内容 + ---------- ---------------- ------------------------------------------------- + 2026/08/21 玄人 幸道 新規作成(#578) +#> +[CmdletBinding()] +param( + [Parameter(Mandatory)] [int]$Port, + [Parameter(Mandatory)] [string]$LogPath, + [string]$User, + [string]$Password, + [string]$MapHost, + [string]$MapTo = "localhost" +) + +$ErrorActionPreference = "Stop" + +$CRLF = [char]13 + [char]10 +$enc = New-Object System.Text.ASCIIEncoding + +function Write-ProxyLog([string]$text) +{ + # **1 行ごとに閉じる。** 開きっぱなしだと、読む側から見えない。 + Add-Content -Path $LogPath -Value $text -Encoding UTF8 +} + +# 資格情報が要るなら、期待値を先に作っておく +$expected = $null +if ($User) +{ + $expected = [Convert]::ToBase64String($enc.GetBytes($User + ":" + $Password)) +} + +# ヘッダ部(CRLFCRLF まで)をバイトで読む。**本体は読まない**(GET/HEAD のみ)。 +function Read-Header($stream) +{ + $buf = New-Object System.Collections.Generic.List[byte] + $one = New-Object byte[] 1 + + while ($true) + { + $n = $stream.Read($one, 0, 1) + if ($n -le 0) { return $null } + + $buf.Add($one[0]) + $c = $buf.Count + + if ($c -ge 4 -and + $buf[$c - 4] -eq 13 -and $buf[$c - 3] -eq 10 -and + $buf[$c - 2] -eq 13 -and $buf[$c - 1] -eq 10) + { + return $enc.GetString($buf.ToArray()) + } + + if ($c -gt 65536) { return $null } # 異常に長いものは捨てる + } +} + +$listener = New-Object System.Net.Sockets.TcpListener([System.Net.IPAddress]::Loopback, $Port) +$listener.Start() + +Write-ProxyLog ("[start] port=" + $Port + " auth=" + $(if ($User) { "basic" } else { "none" })) + +try +{ + while ($true) + { + $client = $listener.AcceptTcpClient() + + try + { + $cs = $client.GetStream() + $cs.ReadTimeout = 15000 + $cs.WriteTimeout = 15000 + + $head = Read-Header $cs + if (-not $head) { continue } + + $lines = $head -split $CRLF + $reqLine = $lines[0] + + # ---- Basic 認証 ---- + if ($expected) + { + $got = $null + foreach ($l in $lines) + { + if ($l -match '^(?i)Proxy-Authorization:\s*Basic\s+(\S+)') { $got = $Matches[1] } + } + + if ($got -ne $expected) + { + Write-ProxyLog ("[407] " + $reqLine) + + $res = "HTTP/1.1 407 Proxy Authentication Required" + $CRLF + + 'Proxy-Authenticate: Basic realm="OpenTouryoSmokeTest"' + $CRLF + + "Content-Length: 0" + $CRLF + + "Connection: close" + $CRLF + $CRLF + + $b = $enc.GetBytes($res) + $cs.Write($b, 0, $b.Length) + $cs.Flush() + continue + } + } + + # ---- 要求行を分解(絶対 URI が来る)---- + $parts = $reqLine -split ' ' + if ($parts.Count -lt 3) { continue } + + $method = $parts[0] + $uri = $null + if (-not [Uri]::TryCreate($parts[1], [UriKind]::Absolute, [ref]$uri)) { continue } + + Write-ProxyLog ($method + " " + $parts[1]) + + # ---- 上流へ繋ぐ ---- + # **別名なら実体へ繋ぎ替える。**(ループバック バイパス回避) + $target = $uri.Host + $mapped = $false + if ($MapHost -and ($uri.Host -eq $MapHost)) { $target = $MapTo; $mapped = $true } + + $up = New-Object System.Net.Sockets.TcpClient + $up.Connect($target, $uri.Port) + $us = $up.GetStream() + $us.ReadTimeout = 15000 + $us.WriteTimeout = 15000 + + # 要求行を相対形に直し、プロキシ用ヘッダを落として転送する。 + $out = $method + " " + $uri.PathAndQuery + " " + $parts[2] + $CRLF + + foreach ($l in $lines[1..($lines.Count - 1)]) + { + if ($l -eq "") { continue } + if ($l -match '^(?i)Proxy-') { continue } + if ($l -match '^(?i)Connection:') { continue } + + # **別名は上流へ渡さない。** 受け付けてもらえない。 + if ($mapped -and ($l -match '^(?i)Host:')) { continue } + + $out += $l + $CRLF + } + + if ($mapped) { $out += ("Host: {0}:{1}" -f $target, $uri.Port) + $CRLF } + + # **どちらも閉じる前提にする。** 使い回しを考えずに済み、実装が単純になる。 + $out += "Connection: close" + $CRLF + $CRLF + + $b = $enc.GetBytes($out) + $us.Write($b, 0, $b.Length) + $us.Flush() + + # ---- 応答を返す ---- + # **「閉じるまで読む」ではいけない。** + # HEAD には本体が無く、上流が接続を保つとタイムアウトまで戻らない。 + # 長さを見て、読むべき分だけ読む。 + $resHead = Read-Header $us + if (-not $resHead) { $up.Close(); continue } + + $hb = $enc.GetBytes($resHead) + $cs.Write($hb, 0, $hb.Length) + + $len = -1 + $chunked = $false + + foreach ($l in ($resHead -split $CRLF)) + { + if ($l -match '^(?i)Content-Length:\s*(\d+)') { $len = [int]$Matches[1] } + if ($l -match '^(?i)Transfer-Encoding:.*chunked') { $chunked = $true } + } + + # HEAD は本体を持たない(Content-Length があっても読まない) + if ($method -eq "HEAD") { $len = 0 } + + $buf = New-Object byte[] 8192 + + if ($len -eq 0) + { + # 何も読まない + } + elseif ($len -gt 0) + { + $rest = $len + while ($rest -gt 0) + { + $want = [Math]::Min($buf.Length, $rest) + $n = $us.Read($buf, 0, $want) + if ($n -le 0) { break } + $cs.Write($buf, 0, $n) + $rest -= $n + } + } + else + { + # 長さ不明(chunked を含む)。閉じるまで読む。 + while ($true) + { + $n = $us.Read($buf, 0, $buf.Length) + if ($n -le 0) { break } + $cs.Write($buf, 0, $n) + } + } + + $cs.Flush() + + $up.Close() + } + catch + { + Write-ProxyLog ("[error] " + $_.Exception.Message) + } + finally + { + $client.Close() + } + } +} +finally +{ + $listener.Stop() +} diff --git a/root/programs/st_Targets.ps1 b/root/programs/st_Targets.ps1 index 4e121e235..23a9d3ae8 100644 --- a/root/programs/st_Targets.ps1 +++ b/root/programs/st_Targets.ps1 @@ -68,6 +68,23 @@ $targetsCS = @( Args = $deployArgs; Expect = '履歴に新規追加しました。' Pre = $startDeployWeb48; Verify = $verifyDeploy48 } + # **プロキシ経由も確かめる。**(#578) + # #575 で HttpWebRequest を HttpClient へ移した際、 + # HttpClientHandler では Proxy = null が「使わない」にならない、という差があった。 + # **配置の成功だけでは足りない。** プロキシを無視して直結しても成功するため、 + # ログに要求が並ぶことまで見る(Test-ProxyUsed)。 + @{ + Name = "DeployZip 配置 プロキシ (net48)"; Bat = "4_Build_Framework_Tool.bat" + Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\OpenTouryo.DeployZipPackWithHTTP.exe" + Args = $deployArgsProxy; Expect = '履歴に新規追加しました。' + Pre = $startProxy48; Verify = $verifyProxy48 + } + @{ + Name = "DeployZip 配置 プロキシ認証 (net48)"; Bat = "4_Build_Framework_Tool.bat" + Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\OpenTouryo.DeployZipPackWithHTTP.exe" + Args = $deployArgsProxyAuth; Expect = '履歴に新規追加しました。' + Pre = $startProxyAuth48; Verify = $verifyProxyAuth48 + } @{ Name = "DeployZip /MFTGEN (net10.0)"; Bat = "4_Build_Framework_ToolCore.bat" Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\net10.0-windows7.0\OpenTouryo.DeployZipPackWithHTTP.exe" @@ -80,6 +97,18 @@ $targetsCS = @( Args = $deployArgs; Expect = '履歴に新規追加しました。' Pre = $startDeployWebCore; Verify = $verifyDeployCore } + @{ + Name = "DeployZip 配置 プロキシ (net10.0)"; Bat = "4_Build_Framework_ToolCore.bat" + Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\net10.0-windows7.0\OpenTouryo.DeployZipPackWithHTTP.exe" + Args = $deployArgsProxy; Expect = '履歴に新規追加しました。' + Pre = $startProxyCore; Verify = $verifyProxyCore + } + @{ + Name = "DeployZip 配置 プロキシ認証 (net10.0)"; Bat = "4_Build_Framework_ToolCore.bat" + Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\net10.0-windows7.0\OpenTouryo.DeployZipPackWithHTTP.exe" + Args = $deployArgsProxyAuth; Expect = '履歴に新規追加しました。' + Pre = $startProxyAuthCore; Verify = $verifyProxyAuthCore + } # --- 通信制御の接続オプション(#546) --- # diff --git a/root/programs/st_Utility.ps1 b/root/programs/st_Utility.ps1 index bcc0cdb38..b6971db47 100644 --- a/root/programs/st_Utility.ps1 +++ b/root/programs/st_Utility.ps1 @@ -437,6 +437,18 @@ function Stop-DeployWeb try { $script:deployWebProc | Stop-Process -Force -EA SilentlyContinue } catch { } $script:deployWebProc = $null } + + # **取り逃がしも消す。**(#578) + # 残った iisexpress は 51084 を握り続ける。 + # 次の起動は 0x800700b7 で失敗するが、**ポートには繋がる**ため + # 起動待ちを通過し、**前回の web フォルダが配られ続ける。** + # 配置は成功するので異常が出ず、判定だけが 0 件になる。 + try + { + Get-Process -Name "iisexpress" -EA SilentlyContinue | + Stop-Process -Force -EA SilentlyContinue + } + catch { } } # ZIP を作るのは対象と同じ実行ファイル(net48 / .NET 10 のそれぞれで確かめる) @@ -455,6 +467,160 @@ $startDeployWebCore = { [void](Start-DeployWeb "core") } $verifyDeploy48 = { $r = Test-Deploy "net48"; Stop-DeployWeb; return $r } $verifyDeployCore = { $r = Test-Deploy "core"; Stop-DeployWeb; return $r } +# ------------------------------------------------------------------ +# プロキシ経由の配置(#578) +# ------------------------------------------------------------------ +# **#575 で HttpWebRequest を HttpClient へ移した経路の確認。** +# HttpClientHandler では Proxy = null が「使わない」にならず +# UseProxy = false が要る、という差があったため、実際に通して確かめる。 +$deployProxyPort = 51085 +$deployProxyUser = "pxuser" +$deployProxyPwd = "pxpass" + +# **localhost を使わない。**(#578) +# .NET Framework の WebProxy は**ループバック宛を無条件にバイパスする** +# (BypassProxyOnLocal = False でも IsBypassed が True)。 +# localhost のままだと net48 ではプロキシを通らず、経路を確かめられない。 +# hosts は書き換えず、**プロキシ側で 127.0.0.1 に繋ぎ替える**(st_Proxy.ps1 -MapHost)。 +$deployHostAlias = "deploy.smoketest" + +function Get-ProxyLog([string]$tag) +{ + return (Join-Path $OutputDir ("deploy_proxy_{0}.log" -f $tag)) +} + +function Stop-DeployProxy +{ + if ($null -ne $script:deployProxyProc) + { + try { $script:deployProxyProc | Stop-Process -Force -EA SilentlyContinue } catch { } + $script:deployProxyProc = $null + } + + # **取り逃がしも消す。** + # 前回の実行が異常終了すると待ち受けを握ったまま残り、 + # 次の起動が黙って失敗する(ポートは繋がるので気づけない)。 + try + { + Get-CimInstance Win32_Process -Filter "Name='powershell.exe' OR Name='pwsh.exe'" -EA SilentlyContinue | + Where-Object { $_.CommandLine -like "*st_Proxy.ps1*" } | + ForEach-Object { Stop-Process -Id $_.ProcessId -Force -EA SilentlyContinue } + } + catch { } +} + +function Start-DeployProxy([string]$tag, [bool]$auth) +{ + # **前回の残りを先に止める。** 掴んだままだと待ち受けに失敗する。 + Stop-DeployProxy + + $log = Get-ProxyLog $tag + if (Test-Path $log) { Remove-Item $log -Force -EA SilentlyContinue } + + $ps1 = Join-Path $PSScriptRoot "st_Proxy.ps1" + + # **利用者の既定は 5.1 だが、ここは疎通の足場なので実行中のホストに合わせる。** + $host_ = if ($PSVersionTable.PSVersion.Major -ge 6) { "pwsh" } else { "powershell" } + + $a = @("-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $ps1, + "-Port", $deployProxyPort, "-LogPath", $log, + "-MapHost", $deployHostAlias) + if ($auth) { $a += @("-User", $deployProxyUser, "-Password", $deployProxyPwd) } + + $script:deployProxyProc = Start-Process $host_ -ArgumentList $a -PassThru -WindowStyle Hidden + + # 起動を待つ。 + # + # **TCP で繋がるかだけでは足りない。**(Start-DeployWeb とは事情が違う) + # 前回のプロキシが待ち受けを握ったままだと接続は成功するが、 + # こちらのプロセスは「ポート使用中」で死んでいる。 + # **自分のログに [start] が出るまで待つ。** + for ($i = 0; $i -lt 40; $i++) + { + Start-Sleep -Milliseconds 300 + + if ($script:deployProxyProc.HasExited) { return $false } + + if (Test-Path $log) + { + $head = @(Get-Content $log -TotalCount 5 -EA SilentlyContinue) + if ($head | Where-Object { $_ -match "\[start\]" }) { return $true } + } + } + + return $false +} + +# **配置が成功しただけでは足りない。** +# プロキシを無視して直結しても成功するため、 +# ログに要求 URL が並ぶことまで見て「経路を通った」と言える。 +function Test-ProxyUsed([string]$tag, [bool]$auth) +{ + $log = Get-ProxyLog $tag + + if (-not (Test-Path $log)) + { + Write-Host " プロキシのログが無い : $log" + return $false + } + + $lines = @(Get-Content $log -EA SilentlyContinue) + $hit = @($lines | Where-Object { $_ -match ("http://{0}:{1}/" -f $deployHostAlias, $deployWebPort) }) + + if ($hit.Count -eq 0) + { + Write-Host " プロキシを経由していない(ログに要求が無い)" + return $false + } + + # マニフェストと ZIP の両方が通っていること + if (-not ($hit | Where-Object { $_ -match "\.mft" })) + { + Write-Host " マニフェストの要求がプロキシを通っていない" + return $false + } + + if (-not ($hit | Where-Object { $_ -match "\.zip" })) + { + Write-Host " ZIP の要求がプロキシを通っていない" + return $false + } + + if ($auth) + { + # **407 が出ていること**が、資格情報の経路を通った証拠になる。 + if (-not ($lines | Where-Object { $_ -match "^\[407\]" })) + { + Write-Host " 407 が記録されていない(認証を要求できていない)" + return $false + } + } + + return $true +} + +# **WWWURL も別名にする。** localhost のままではバイパスされる。 +$deployArgsProxy = @("/CUI", "/NB", "/FORCE", "/WWWURL", + ("http://{0}:{1}/FormAppRoot.mft" -f $deployHostAlias, $deployWebPort), + "/ProxyURL", ("http://localhost:{0}" -f $deployProxyPort)) + +$deployArgsProxyAuth = $deployArgsProxy + @("/ProxyUID", $deployProxyUser, + "/ProxyPWD", $deployProxyPwd) + +$startProxy48 = { if (-not (Start-DeployProxy "net48" $false)) { throw "プロキシを起動できません(port $deployProxyPort)" } + if (-not (Start-DeployWeb "net48")) { throw "配信サーバを起動できません(port $deployWebPort)" } } +$startProxyCore = { if (-not (Start-DeployProxy "core" $false)) { throw "プロキシを起動できません(port $deployProxyPort)" } + if (-not (Start-DeployWeb "core")) { throw "配信サーバを起動できません(port $deployWebPort)" } } +$startProxyAuth48 = { if (-not (Start-DeployProxy "net48auth" $true)) { throw "プロキシを起動できません(port $deployProxyPort)" } + if (-not (Start-DeployWeb "net48")) { throw "配信サーバを起動できません(port $deployWebPort)" } } +$startProxyAuthCore = { if (-not (Start-DeployProxy "coreauth" $true)) { throw "プロキシを起動できません(port $deployProxyPort)" } + if (-not (Start-DeployWeb "core")) { throw "配信サーバを起動できません(port $deployWebPort)" } } + +$verifyProxy48 = { $r = (Test-Deploy "net48") -and (Test-ProxyUsed "net48" $false); Stop-DeployWeb; Stop-DeployProxy; return $r } +$verifyProxyCore = { $r = (Test-Deploy "core") -and (Test-ProxyUsed "core" $false); Stop-DeployWeb; Stop-DeployProxy; return $r } +$verifyProxyAuth48 = { $r = (Test-Deploy "net48") -and (Test-ProxyUsed "net48auth" $true); Stop-DeployWeb; Stop-DeployProxy; return $r } +$verifyProxyAuthCore = { $r = (Test-Deploy "core") -and (Test-ProxyUsed "coreauth" $true); Stop-DeployWeb; Stop-DeployProxy; return $r } + # ------------------------------------------------------------------ # WebAPI(バッチ更新)のホスト(#570) # ------------------------------------------------------------------