summaryrefslogtreecommitdiff
path: root/scripts/Verify-PublishedHttp.ps1
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-08-13 18:20:33 +0900
committertanaka takashi <isazaka@gmail.com>2026-08-13 18:20:33 +0900
commit76fdcb43585a4c4d288c1026d318a0ddbe3e26ab (patch)
treef58296832d37b035d3e787e0f270c77b59c89d77 /scripts/Verify-PublishedHttp.ps1
parent78fe349073e3a2e89f0bf14b134ae0955aa7182a (diff)
fix(sandbox): correct cmd descendant handling and protected ACL policy
Replace the earlier cmd-wide descendant incompatibility diagnosis with the verified distinction between drive-qualified paths and PATH/workspace-relative invocation. Document the cmd YAML configuration, executable resolution, --no-runtime approval flow, and safe descendant invocation examples in the user README. Keep the System32 protected DACL intact for both the OS Runtime Root and approved entry files nested below it. Skip redundant file-level ACL rewrites for approved System32 executables while retaining LPAC confinement, resolved-path checks, SHA-256 approval, WFP policy, and Job Object enforcement. Expand Windows coverage with capability positive/negative matrices, protected-DACL regression tests, cmd/PowerShell/venv Python script execution, nine Entry-to-Descendant combinations, network none/local probes, and randomized ACL round-trip testing. Add read-only CLI/README verification and published HTTP MCP agent_run verification scripts. Update Design, Audit Report, and Requirement Traceability with the corrected root cause, current evidence, withdrawn diagnostic conclusions, and the remaining partial item for per-combination descendant self-recorded LPAC SID/Job evidence. Verified: Release build 0 warnings/errors; Core 103 PASS; Planner 10 PASS; Windows 75 PASS with skip 0; README operational suite 19 PASS; published HTTP MCP agent_run completed 3/3 with cmd, curl, C:\tmp\.venv Python, network-none enforcement, ACL restoration, and CMD_HTTP_MCP_OK.
Diffstat (limited to 'scripts/Verify-PublishedHttp.ps1')
-rw-r--r--scripts/Verify-PublishedHttp.ps187
1 files changed, 87 insertions, 0 deletions
diff --git a/scripts/Verify-PublishedHttp.ps1 b/scripts/Verify-PublishedHttp.ps1
new file mode 100644
index 0000000..a02a28b
--- /dev/null
+++ b/scripts/Verify-PublishedHttp.ps1
@@ -0,0 +1,87 @@
+param(
+ [string]$BundlePath = 'build\Release\publish\agent-sandbox-mcp-1.0.0-win-x64',
+ [string]$TestRoot = 'C:\tmp',
+ [string]$EvidenceRoot = 'artifacts\evidence\published-http-cmd-verification'
+)
+
+$ErrorActionPreference = 'Stop'
+$OutputEncoding = [Text.UTF8Encoding]::new($false)
+[Console]::OutputEncoding = $OutputEncoding
+$repository = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
+$bundle = [IO.Path]::GetFullPath((Join-Path $repository $BundlePath))
+$publishRoot = [IO.Path]::GetFullPath((Join-Path $repository 'build\Release\publish'))
+if (-not $bundle.StartsWith($publishRoot + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) {
+ throw 'BundlePath must remain inside build\Release\publish.'
+}
+$testRootPath = (Resolve-Path -LiteralPath $TestRoot).Path
+$evidence = [IO.Path]::GetFullPath((Join-Path $repository $EvidenceRoot))
+if (-not $evidence.StartsWith($repository + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) {
+ throw 'Evidence output must remain inside the repository.'
+}
+$administrator = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
+ [Security.Principal.WindowsBuiltInRole]::Administrator)
+if (-not $administrator) { throw 'Published HTTP verification must run as Windows Administrator.' }
+
+$agent = Join-Path $bundle 'agent-mcp.exe'
+$config = Join-Path $bundle 'agent.yaml'
+$clientProject = Join-Path $repository 'scripts\E2EClient\E2EClient.csproj'
+$runRoot = Join-Path $testRootPath ('agent-mcp-http-cmd-' + [Guid]::NewGuid().ToString('N'))
+$runRootForward = $runRoot.Replace('\', '/')
+$endpoint = 'http://127.0.0.1:8080/mcp'
+$log = Join-Path $evidence 'verification.log'
+$server = $null
+New-Item -ItemType Directory -Force -Path $evidence | Out-Null
+New-Item -ItemType Directory -Path $runRoot | Out-Null
+$aclBefore = (Get-Acl -LiteralPath $runRoot).Sddl
+
+$request = @"
+実作業を行ってください。作業ディレクトリは $runRootForward です。
+file_editで probe.py と run-probe.cmd を作成してください。
+probe.pyはsys.prefixがC:\tmp\.venvであることを検証し、VENV_PYTHON_OKと表示してください。
+run-probe.cmdは次を順番に実行し、どれかが失敗したら非0で終了してください。
+1. 非修飾名 cmd.exe を子Processとして実行する。
+2. 非修飾名 curl.exe --version を子Processとして実行する。
+3. curl.exeで $endpoint へ接続を試み、sandbox.network.access=noneにより失敗することを確認する。接続できた場合は失敗とする。
+4. Workspace相対path ..\.venv\Scripts\python.exe でprobe.pyを実行する。
+最後にInternal Tool process_runを executable=cmd、cwd=$runRootForward、args=["/d","/c","call run-probe.cmd"] で実行し、exit code 0とCMD_HTTP_MCP_OKを確認してください。説明だけで完了せず、必ずファイル作成とprocess_runを実行してください。
+"@
+
+try {
+ & $agent check --config $config --lang ja 2>&1 | Tee-Object -FilePath $log
+ if ($LASTEXITCODE -ne 0) { throw "Published check failed with exit code $LASTEXITCODE." }
+
+ $server = Start-Process -FilePath $agent -ArgumentList @('serve','--config',$config,'--lang','ja','--transport','http') `
+ -WorkingDirectory $bundle -WindowStyle Hidden -PassThru
+ $ready = $false
+ for ($attempt = 0; $attempt -lt 100; $attempt++) {
+ if ($server.HasExited) { throw "Published server exited before readiness: $($server.ExitCode)" }
+ try {
+ $response = Invoke-WebRequest -Uri $endpoint -Method Get -SkipHttpErrorCheck
+ if ($response.StatusCode -eq 405) { $ready = $true; break }
+ }
+ catch { }
+ Start-Sleep -Milliseconds 100
+ }
+ if (-not $ready) { throw 'Published HTTP MCP server did not become ready.' }
+
+ dotnet run --project $clientProject -c Release --no-build -- http $endpoint unused $request 2>&1 |
+ Tee-Object -FilePath $log -Append
+ if ($LASTEXITCODE -ne 0) { throw "HTTP MCP agent_run failed with exit code $LASTEXITCODE." }
+ if (-not (Test-Path -LiteralPath (Join-Path $runRoot 'probe.py')) -or
+ -not (Test-Path -LiteralPath (Join-Path $runRoot 'run-probe.cmd'))) {
+ throw 'MCP Task did not create the required verification files.'
+ }
+}
+finally {
+ if ($server -and -not $server.HasExited) { $server.Kill($true); $server.WaitForExit() }
+ if (Test-Path -LiteralPath $runRoot) {
+ if ((Get-Acl -LiteralPath $runRoot).Sddl -ne $aclBefore) { throw 'MCP Task did not restore the test directory ACL.' }
+ $resolvedRunRoot = (Resolve-Path -LiteralPath $runRoot).Path
+ if (-not $resolvedRunRoot.StartsWith($testRootPath.TrimEnd('\') + '\', [StringComparison]::OrdinalIgnoreCase)) {
+ throw 'Refusing to clean a test directory outside TestRoot.'
+ }
+ Remove-Item -LiteralPath $resolvedRunRoot -Recurse -Force
+ }
+}
+
+Write-Output "Published HTTP MCP cmd verification PASS. Evidence: $evidence"