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)
# ------------------------------------------------------------------