summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-08-13 22:48:24 +0900
committertanaka takashi <isazaka@gmail.com>2026-08-13 22:48:24 +0900
commit9337ac3e5edd42bb17f5e2ade6c2de02c7ef576d (patch)
tree9a48fefc88cc046f4ce1e2bc34fa0a47351e4f83 /doc
parent36ae1a4cba791ec633a81b38b1d8345af8487276 (diff)
feat!: isolate privileged sandbox network operations per task
Run agent-mcp with an explicit asInvoker manifest and move WFP and loopback mutations into a fixed requireAdministrator helper under the release admin directory. Add the Agent.Admin client and host projects with task-scoped runas launch, a logon-SID and Administrators-only local named pipe, remote-client rejection, mutual PID validation, strict versioned JSON framing, fixed network-only operations, and bounded messages. Delay ACL and network Task Resource application until the first process_run. Verify executable identity, managed entry points, DNS snapshots, and normal-token WRITE_DAC access before elevation; reuse the helper only within the Task and keep elevation failures terminal without policy replanning. Keep LPAC creation, executable approval, Job confinement, and ACL leases in the normal process. Make startup platform checks read-only, create the fixed Application Profile during apply, preserve dynamic WFP lifetime in the helper, and route persistent loopback recovery through the same elevated boundary. Update recovery journaling, localized elevation and IPC errors, audit events, release publishing, manifests, README guidance, Specifications, Design, implementation records, and requirement traceability for the on-demand elevation model. Add administrative-boundary, file-only no-elevation, elevation-terminal, lazy-resource, crash-recovery, manifest, IPC schema, and operational verification coverage. Verified Release build with zero warnings, Core 105/105, Planner 10/10, administrative boundary 4/4, elevated Windows suite 79/79, and published stdio/HTTP MCP E2E.
Diffstat (limited to 'doc')
-rw-r--r--doc/AuditReport.md4
-rw-r--r--doc/Design.md34
-rw-r--r--doc/Specifications.md21
3 files changed, 46 insertions, 13 deletions
diff --git a/doc/AuditReport.md b/doc/AuditReport.md
index 3cbed19..2155236 100644
--- a/doc/AuditReport.md
+++ b/doc/AuditReport.md
@@ -1,5 +1,9 @@
# v1再監査報告とSandbox Usability Revision状況
+> 2026-08-13オンデマンド昇格改定: 以下の管理者環境証跡は常時管理者方式の過去commitに対する履歴である。`asInvoker` main、Task単位helper、Named Pipe、dynamic WFP、persistent loopback Recoveryは最新commitで再検証するまでPASS根拠としない。
+
+2026-08-13 working treeでmainを`asInvoker`、昇格hostを`requireAdministrator/uiAccess=false`とし、WFP/loopback mutationを固定`admin/` hostへ分離した。通常tokenのHTTP/stdio MCPから実Taskを実行し、初回`process_run`時のUAC、logon SID DACL Named Pipe、LPAC Process Tree、dynamic WFP、ACL/WFP cleanupを確認した。Windows suiteは昇格子Processだけで79件PASS、Core 105件、Planner 10件、administrative boundary 4件がfail/skip 0。実UAC拒否、hostile peer実Process matrix、実helper crashからのstartup Recoveryは未再検証のため、TraceabilityではPARTIALを維持する。
+
> 2026-08-13 schema version 2追補: YAMLを唯一のSandbox desired stateとし、個別のExecutable Approval/Sandbox Resolution操作を廃止した。CLIはcommand省略のServer起動、`apply`、`show`に限定し、確認結果はconfig別Applied Configuration Storeへ一括保存する。本追補より前の管理者・publish証跡は旧schemaの履歴であり、schema version 2のPASS根拠ではない。最終検証はRelease build warning/error 0、Core 104件、Planner 10件、Windows Security/Recovery 56件、README operational 19件がfail/skip 0。publish HTTP MCPも`deepseek-v4-flash:cloud`でcompleted 3/3となり、cmd→cmd/curl/venv Python、Network none、終了後残留0を確認した。
## 基準
diff --git a/doc/Design.md b/doc/Design.md
index 80b5acc..5a8d0f0 100644
--- a/doc/Design.md
+++ b/doc/Design.md
@@ -93,8 +93,9 @@ Agent Runtime ─── Session Store (memory)
├── Less Privileged AppContainer (LPAC)
├── NTFS ACL
├── Job Object
- ├── WFP
- └── Named Pipe
+ └── Named Pipe ── Task単位runas Process
+ ├── WFP dynamic session
+ └── loopback exemption
│
▼
Sandbox Process Tree
@@ -121,6 +122,7 @@ src/
Agent.Core/ # Agent loop, session, prompt, ollama abstractions
Agent.Planner/ # TaskGraph, TokenPERT, TokenCPM
Agent.Windows/ # SandboxPolicy enforcement and Win32 interop
+ Agent.Admin/ # Sandbox Brokerの固定network処理を行う通常clientと昇格host
tests/
Agent.Core.Tests/
Agent.Planner.Tests/
@@ -140,6 +142,7 @@ state/
```text
Agent.App -> Agent.Mcp -> Agent.Core -> Agent.Planner
Agent.App -------------------------> Agent.Windows
+Agent.App / Agent.Windows ---------> Agent.Admin.Client
Agent.Core -> ISandbox/IToolExecutor interfaces
Agent.Windows implements those interfaces
```
@@ -234,7 +237,7 @@ result: <final natural-language answer; completed only>
### 5.8 起動preflightとHTTP request log
-- Appはtransport構築前に`WindowsPlatformCheck`を実行する。administrator/BFE/WFP probeが1つでも失敗した場合はhostをbuild/startせずfatalとする。
+- Appはtransport構築前に`WindowsPlatformCheck`を実行し、OS、Application Profile、BFE read-only open、固定Bundle pathの昇格用Executableとversionを検査する。Administrator判定、WFP transaction、filter add/delete probeは行わない。
- `StartAsync`完了後にだけ`IMcpHostObserver.Ready`を通知するため、「起動中」と「接続可能」を区別できる。
- HTTP middlewareはsocket endpointとrouting metadataだけをbounded in-memory queueへ`TryWrite`し、専用background writerがstderr、application log、`logs/http.jsonl`へ出力する。request threadはconsole/file I/Oを待たず、queue飽和時はrequestを止めずlog entryをdropして件数を警告する。
- forwarded header、credential header、query、payloadは保存しない。
@@ -539,7 +542,7 @@ network:
- reparse chainを最終targetまで解決しcycle、missing target、非local filesystemを拒否する。
- `agent-mcp apply [config] [--yes]`だけがApplied Configuration Storeを更新する。全解決・validation完了前、または確認前にStoreを変更しない。
- `agent-mcp [config]`は現在のYAMLを再解決・再hashし、Applied Configuration snapshotとの完全一致とWindows preflightを検証してからMCP受付を開始する。個別の`serve`と`check`commandは持たない。
-- `agent-mcp show [config]`はdesired/resolved/appliedの権限matrixをtext表示し、StoreやACL/WFPを変更しない。管理者権限、BFE、WFP add/deleteを伴う完全なWindows preflightはServer起動時だけ実行する。
+- `agent-mcp show [config]`はdesired/resolved/appliedの権限matrixをtext表示し、StoreやACL/WFPを変更せずUACを発生させない。`apply`は通常ユーザー権限で固定Application Profileを作成または確認してApplied Configurationを保存する。Server起動時は固定SIDの導出、BFE open、helper整合性のread-only preflightだけを行う。
- languageとtransportはYAMLだけから取得し、CLI overrideを持たない。
### 10.7 Effective Sandbox Policy
@@ -607,9 +610,13 @@ WFP実装は複雑な汎用Firewallにしない。設計上の変換規則だけ
5. DNS解決失敗はdeny。
6. Task終了でTask固有WFP filterを削除する。
7. LoopbackもEffective Network Policyに明示されない限り許可しない。LANをlocalへ含めない。
-具体的なWFP layer、sublayer、filter condition、transaction APIは実装時にCodexがWindows SDKを確認して決定し、Security Integration Testで仕様を検証する。
+WFP mutationはTask内の初回`process_run`直前に`runas`で起動する昇格Processが行う。Task間でProcessを再利用せず、dynamic sessionをTask終了まで保持する。session終了時にBFEがdynamic objectを削除するため、filter IDをRecovery Journalへ保存しない。
+
+`local`はLPAC network capability、`NetworkIsolationSetAppContainerConfig`によるAppContainer loopback送信許可、WFPによる`127.0.0.1`/`::1`の列挙port制限を組み合わせる。同APIは既存SID集合をGetして保持し、Application Profile SIDの追加前状態をRecovery Journalへ記録・復元する。Microsoft資料の`debugging purposes`という用途制約を既知制約とし、同API自体はSecurity Boundaryとしない。WFP permit単独、MSIX、独自proxyへfallbackしない。
### 11.6 Named Pipe
-Sandbox workerとのIPCが必要な場合はtask固有Named Pipeを使用し、DACLをApplication SIDとBrokerだけに限定する。TCP localhostを内部IPCに使わない。
+通常側がTask固有Named Pipe serverを明示DACL付きで作成し、昇格Processだけがclient接続する。DACLはlogon SIDとAdministratorsへ必要最小権限を与え、NETWORKをdenyし、default DACLを使用しない。通常側は`ShellExecuteEx/runas`相当で得たProcess IDと`GetNamedPipeClientProcessId`を照合し、昇格側もparent PIDと`GetNamedPipeServerProcessId`を照合する。
+
+protocolはversion、Task ID、固定Application SID、Network Access Mode、解決済みIP/port、loopback復元状態を持つ長さ上限付きmessageに限定する。任意Executable、command、path、Security Descriptor、Registry、WFP layer/sublayer/action、Configuration/Policyを表現できるfieldを持たない。TCP localhost、独自RPC、汎用Network proxyへ拡張しない。
---
## 12. ACL / Resource Transaction設計
### 12.1 ACIDから借用する性質
@@ -623,7 +630,7 @@ Sandbox workerとのIPCが必要な場合はtask固有Named Pipeを使用し、D
```text
CLEAN
-> PREPARING journal create
- -> APPLIED ACL/WFP/Job ready
+ -> APPLIED 初回process_run直前にACL/WFP/Job ready
-> RUNNING sandbox process start
-> CLEANING process stopped / task terminal
-> CLEAN all task resources removed
@@ -638,12 +645,13 @@ JournalはTaskごとのJSONとし、操作を実行する**前**にundoに必要
"task_id": "...",
"state": "APPLIED",
"acl_changes": [{"path":"...","change_id":"..."}],
- "wfp_filter_ids": [123],
+ "network_loopback_before": false,
"temp_paths": ["..."],
"created_at": "..."
}
```
起動時にjournalが存在する場合、MCP transport開始前にRecovery Managerが逆順でcleanupし、全項目の不存在/復元を検査してからjournalを削除する。
+ACL/file/tempだけなら通常権限で復旧する。persistentなloopback entryがあれば起動時だけ昇格Processを起動して復旧し、UAC拒否時はMCP受付前にfatal終了する。WFP dynamic entryの旧Journalはupgrade互換のno-opとしてclean化する。
---
## 13. File Transaction設計
### 13.1 基本フロー
@@ -699,7 +707,7 @@ Auditはappend-only JSONLを採用する。1 event = 1 line。
{"ts":"...","event":"file.write","task_id":"...","path":"...","before_sha256":"...","after_sha256":"..."}
{"ts":"...","event":"policy.deny","task_id":"...","kind":"network","target":"example.com:443","reason":"not_allowlisted"}
```
-最低event集合: `task.start`, `task.end`, `tool.call`, `process.start`, `process.exit`, `file.write`, `file.delete`, `policy.deny`, `network.rule.apply`, `network.rule.remove`, `recovery.start`, `recovery.end`。各eventは可能な限りsession ID、task ID、内部error codeを持つ。
+最低event集合: `task.start`, `task.end`, `tool.call`, `process.start`, `process.exit`, `file.write`, `file.delete`, `policy.deny`, `network.rule.apply`, `network.rule.remove`, `recovery.start`, `recovery.end`, `sandbox.elevation.request`, `sandbox.elevation.success`, `sandbox.elevation.deny`, `sandbox.ipc.reject`。各eventは可能な限りsession ID、task ID、内部error codeを持つ。pipe名、IPC payload全文、UAC credentialは記録しない。
---
## 16. Recovery・終了設計
### 16.1 graceful stop
@@ -790,6 +798,11 @@ closed Sessionは再利用しない。プロセス再起動後に以前のSessio
| ST-25 | Entry (`PowerShell`/Python/.NET/`cmd`) × Descendant (`cmd`/PowerShell/Python/.NET/System32 utility) | 個別Approvalなしで起動し、Descendantが同じLPAC SID/Jobに残る。cmd内からはPATH解決名またはWorkspace相対pathを使用する |
| ST-26 | protected DACL root/descendantと通常DACL rootのread/write/execute | protected bitを解除せず、許可ケースだけ成功。適用不能ケースは拒否し、cleanup後Security Descriptorが完全一致 |
| ST-27 | baseline/Network capabilityの追加前後 | 必要な正方向ケースに加えFilesystem、Registry write、COM、Policy外Network、Job breakawayの負方向集合をすべて検証 |
+| ST-28 | 通常tokenでのstdio/HTTP、show/apply、file-only Task | ServerとTaskが成功しUACが発生しない |
+| ST-29 | Taskごとの初回/後続process_runとUAC拒否 | 初回だけ昇格し、同一Task内でhelperを再利用する。拒否は当該Taskだけfailed |
+| ST-30 | helper crash、main crash、startup Recovery | WFP残留0、loopbackを元状態へ復元、Recovery UAC拒否はbind前fatal |
+| ST-31 | Named Pipeのremote/別PID/別session/version/size/reconnect/double-apply | すべて拒否し、固定network操作以外をschemaで表現不能 |
+| ST-32 | main/helper manifest、bundle path/version、native call graph | asInvoker/requireAdministrator、固定admin配置、WFP/loopback mutationがhelper側だけに存在 |
---
## 20. エラー分類
| Category | 例 | Task結果 | Retry |
@@ -818,8 +831,9 @@ errorは内部codeとlocalized messageを分離し、ログ/auditにはcode、MC
| 10 | Release/Operational E2E | self-contained Bundle単独起動、stdio/HTTP実利用 |
### 21.1 Release設計
-- `dotnet publish -c Release -r win-x64 --self-contained true` のfolder publishを配布元とする。
+- mainと昇格hostを同じversion/RIDで`dotnet publish -c Release -r win-x64 --self-contained true`し、mainをBundle root、昇格hostを固定`admin/` subdirectoryへ配置する。
- Bundleはversion付きZIP、展開済みdirectory、file manifest、SHA-256 checksumから成る。
+- main manifestは`asInvoker`、`admin/agent-mcp-admin.exe` manifestは`requireAdministrator`かつ`uiAccess=false`とする。mainは`AppContext.BaseDirectory/admin/agent-mcp-admin.exe`だけを参照し、PATH検索やConfigurationによる差替えを許さない。
- 起動時の相対pathは実行ファイルdirectoryを基準に解決し、ソースツリーを参照しない。
- 現行Operational E2Eは配布既定の`deepseek-v4-flash:cloud`を使用する。rate limit、接続失敗、model unavailableをapplication PASSとして扱わない。
---
diff --git a/doc/Specifications.md b/doc/Specifications.md
index fb1de12..dcc2425 100644
--- a/doc/Specifications.md
+++ b/doc/Specifications.md
@@ -188,7 +188,7 @@ command省略時はYAMLの`mcp.transport`と`application.language`を使用しã�
`apply`はbase/local merge後のYAML全体、Workspace、Mount、Execution Entry、Network、Resourceを解決し、ExecutableのResolved PathとSHA-256を含む権限差分を一度だけ表示する。全検証成功後、利用者が承認した場合だけconfig別Applied Configuration Storeをatomic replaceする。途中失敗時は以前の適用状態を維持する。`--yes`は非対話適用だけに使用でき、Auditへ記録する。
-`show`はread-onlyとし、desired/resolved/applied/effectiveの状態とFilesystem/Execution/Network/Resource権限マトリックスを一つのtext表示で返す。WFP filter追加削除を伴う完全なPlatform preflightは起動時に必ず実施する。MCP ClientおよびLLMから`apply`を呼び出せない。
+`show`はread-onlyとし、desired/resolved/applied/effectiveの状態とFilesystem/Execution/Network/Resource権限マトリックスを一つのtext表示で返す。`show`と`apply`はUACを発生させない。MCP ClientおよびLLMから`apply`を呼び出せない。
旧`serve`、`check`、`executable *`、`sandbox *`、`--config`、`--lang`、`--transport`、`--path`、`--runtime-root`、`--no-runtime`、`--format`は受け付けず、schema version 2の移行診断を返す。
@@ -206,7 +206,8 @@ command省略時はYAMLの`mcp.transport`と`application.language`を使用しã�
### 5.8 起動・HTTP観測性
-- command省略のServer起動はbind前に管理者権限、BFE、WFP transaction、filter add/deleteを検査し、不足時は具体的なerrorと対処をstderrへ出してexit code 2で終了しなければならない。
+- `agent-mcp.exe`は`asInvoker`で通常ユーザー権限のまま起動し、MCP Clientに管理者権限を要求しない。
+- command省略のServer起動はbind前にOS、Configuration、Applied Configuration、Effective Sandbox Policy、Application Profile、BFE、昇格用Executableの存在・互換version、Recovery Journalをread-only検査する。WFPを書き換えるprobeを起動時に行わない。
- ready messageは実際のtransport開始後だけ出力し、HTTPではendpoint/protocol/stateless/PID/log path、stdioではprotocol/PID/log pathを含める。
- HTTP request logは実socketのremote/local endpoint、method、path、status、duration、標準MCP routing headerを記録可能とする。
- `Authorization`、`Cookie`、query、body、prompt、画像、Base64をrequest logへ記録してはならず、`X-Forwarded-For`を接続元として信用してはならない。
@@ -444,6 +445,9 @@ Resource Profileは`constrained = 1024 MiB/4 Process/300秒`、`normal = 4096 Mi
- Resolved `%SystemRoot%/System32`をOS Runtime RootとしてSandbox Process Treeへread/execute公開する。Brokerからの直接Entry起動は別途Executable Approvalを要求する。
- Task終了時にApplication Profileを削除しない。
- Task固有ACL、WFP filter、Job Object、一時ファイル等はTask Resourceとして管理する。
+- LPAC Process Treeに必要なTask ResourceはTask内の初回`process_run`直前に適用する。Processを使用しないTaskはUACを発生させない。
+- WFP書込と現在昇格して行うsystem-wide loopback設定だけをTask単位で昇格し、ACL、LPAC Process生成、Job Object、Executable Approvalは通常権限で処理する。
+- Task時のUAC拒否または昇格用Executable起動失敗では当該Taskだけをfailedとし、部分適用ResourceをrollbackしてServerを継続する。
- Task Resourceは正常終了・失敗・cancelのいずれでも残留させない。
- crashで残留可能性がある変更はRecovery Journalにより次回起動時に回収する。
- MCP受付開始前にRecoveryを完了し、clean stateを確認しなければならない。
@@ -490,7 +494,7 @@ Resource Profileは`constrained = 1024 MiB/4 Process/300秒`、`normal = 4096 Mi
| --- | --- |
| Application Log | stderrに出力可能。stdio時stdoutへログを出してはならない。ファイルにも保存する。 |
| LLM Log | promptとresponseを記録する。call、Session、Task、Planner Task、phase、iteration、replan、model、token usageを相関できなければならない。secretを継承しない前提でも、ログ出力先は保護する。 |
-| Audit Log | 通常ログと分離する。Task lifecycle、Internal Tool Call、Sandbox Process、秘密情報を除いたargument metadata、exit code、file write、delete、denied access、network rule、recoveryをSession/Taskと相関して記録する。argument本文、画像、Base64、credentialは記録しない。 |
+| Audit Log | 通常ログと分離する。Task lifecycle、Internal Tool Call、Sandbox Process、秘密情報を除いたargument metadata、exit code、file write、delete、denied access、network rule、昇格要求・結果、IPC拒否、recoveryをSession/Taskと相関して記録する。argument本文、画像、Base64、credential、pipe認証情報、IPC payload全文は記録しない。 |
| Token Metrics | Task/Call単位のinput/output/total tokenを記録する。 |
---
@@ -506,6 +510,8 @@ Resource Profileは`constrained = 1024 MiB/4 Process/300秒`、`normal = 4096 Mi
| REC-05 | Streamable HTTP server停止/明示cancel | 対象Taskを安全停止する。stateless HTTPのrequest完了やsocket切断はAgent Session終了とみなさない。 |
| REC-06 | crash後起動 | Recovery Journalに基づき残留Task Resourceをcleanにしてからserveする。 |
| REC-07 | cleanup失敗 | serveを開始せずfatal errorとする。 |
+| REC-08 | Task時UAC拒否 | 当該Taskをfailedとし、rollback後もMCP Serverを継続する。 |
+| REC-09 | 起動時RecoveryのUAC拒否 | Recovery未完了としてMCP受付前にfatal終了する。 |
---
@@ -526,6 +532,10 @@ Resource Profileは`constrained = 1024 MiB/4 Process/300秒`、`normal = 4096 Mi
| SEC-INV-11 | Recovery未完了状態でMCP受付を開始しない。 |
| SEC-INV-12 | stdio stdoutにはMCP protocol以外を書かない。 |
| SEC-INV-13 | Sandbox Process TreeのどのProcessもEffective Sandbox Policy外のresourceまたはcapabilityを取得できない。 |
+| SEC-INV-14 | MCP Server本体は管理者tokenを必要とせず、LLM、MCP Client、Internal Toolは昇格用Executableへ直接要求できない。 |
+| SEC-INV-15 | 昇格側は任意Executable、command line、Filesystem path、Security Descriptor、Registry、User Sandbox Configuration、Effective Sandbox Policyを操作できない。 |
+| SEC-INV-16 | 昇格側のnetwork変更は固定Application Profileと確定済みEffective Network Policyから導出されるものに限定する。 |
+| SEC-INV-17 | 未許可ProcessはTask固有Named Pipeを利用できず、昇格Process異常終了後にWFP dynamic objectを残さない。 |
---
@@ -571,6 +581,11 @@ Resource Profileは`constrained = 1024 MiB/4 Process/300秒`、`normal = 4096 Mi
| AT-18 | ja/en切替がCLI、MCP応答、LLM回答へ反映される。 |
| AT-19 | 追加localeがコード変更なしでロードされる。 |
| AT-20 | 未知locale keyまたは壊れたJSONで起動/checkが失敗する。 |
+| AT-23 | `agent-mcp.exe`とstdio/HTTP MCP Clientを通常tokenで起動でき、`show`、`apply`、Processを使わないTaskではUACが発生しない。 |
+| AT-24 | 初回`process_run`直前だけTask専用の昇格用Executableが起動し、同一Taskでは再利用され、次Taskへは再利用されない。UAC拒否またはhelper失敗は当該Taskだけをfailedにする。 |
+| AT-25 | mainは`asInvoker`、昇格用Executableは`requireAdministrator`かつ`uiAccess=false`であり、Release Bundleの固定`admin/`配置以外を起動しない。 |
+| AT-26 | Named Pipeのremote接続、peer PID不一致、protocol/version不一致、過大message、再接続、二重network適用を拒否する。 |
+| AT-27 | helper異常終了後にdynamic WFP objectが残らず、persistent loopback変更はRecovery Journalから復元される。Recovery時UAC拒否はMCP受付前fatalとなる。 |
### 20.1 Operational E2E