From b56614c814b904c224315a11f9686f0d47abd3d3 Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Wed, 12 Aug 2026 05:44:54 +0900 Subject: feat: revise sandbox usability around semantic policy and LPAC process trees Rewrite the specification and design vocabulary around User Sandbox Configuration, Environment Resolution, Executable Approval, Effective Sandbox Policy, and Windows Enforcement. Move the Internal Tool catalog to the design without treating its count as a requirement, and update README, implementation planning, traceability, audit history, prompts, and the Python skill. Introduce schema_version 1 profiles, workspaces, mounts, executable aliases, network modes, and resource presets. Add local override merging, resolution and approval stores with atomic user-only persistence, fail-closed fingerprints, localized diagnostics, and executable/sandbox management CLI commands. Change Windows execution to LPAC entry approval with inherited descendant confinement. Separate read and execute ACLs, preserve protected OS DACLs, apply Job process/memory/timeout limits to the tree, enforce WFP network modes, prevent credential environment inheritance, disable out-of-tree MSBuild reuse, and harden transactional ACL/recovery cleanup. Isolate planning prompts from execution instructions, reject split coding plans that cannot satisfy task-scoped evidence, preserve configured thinking, and prevent optional task_update failures from corrupting completion checks. Add and update configuration, resolution, approval, LPAC, descendant, readonly/development, Registry/COM, WFP, recovery, .NET/Python/PowerShell process-tree, and Operational E2E coverage. Publish reproducible bundles while preserving deployment-local configuration, prompts, skills, logs, state, approvals, and resolutions. --- scripts/Publish-Release.ps1 | 47 ++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'scripts/Publish-Release.ps1') diff --git a/scripts/Publish-Release.ps1 b/scripts/Publish-Release.ps1 index a36c2b4..d794bb5 100644 --- a/scripts/Publish-Release.ps1 +++ b/scripts/Publish-Release.ps1 @@ -15,22 +15,18 @@ $bundleName = "agent-sandbox-mcp-$Version-win-x64" $bundle = Join-Path $outputRootPath $bundleName $zip = Join-Path $outputRootPath "$bundleName.zip" $checksum = "$zip.sha256" +$stagingRoot = Join-Path $outputRootPath (".staging-" + [Guid]::NewGuid().ToString('N')) +$stagingBundle = Join-Path $stagingRoot $bundleName New-Item -ItemType Directory -Force -Path $outputRootPath | Out-Null -if (Test-Path -LiteralPath $bundle) { - $resolvedBundle = (Resolve-Path -LiteralPath $bundle).Path - if (-not $resolvedBundle.StartsWith($outputRootPath + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { - throw 'Existing Release Bundle escaped the validated output root.' - } - Get-ChildItem -LiteralPath $resolvedBundle -Force | Remove-Item -Recurse -Force -} if (Test-Path -LiteralPath $zip) { Remove-Item -LiteralPath $zip -Force } if (Test-Path -LiteralPath $checksum) { Remove-Item -LiteralPath $checksum -Force } +New-Item -ItemType Directory -Path $stagingBundle | Out-Null $appProject = Join-Path $repository 'src\Agent.App\Agent.App.csproj' dotnet restore $appProject -r win-x64 --locked-mode if ($LASTEXITCODE -ne 0) { throw "win-x64 locked restore failed with exit code $LASTEXITCODE" } -dotnet publish $appProject -c Release -r win-x64 --self-contained true --no-restore --output $bundle -p:Version=$Version +dotnet publish $appProject -c Release -r win-x64 --self-contained true --no-restore --output $stagingBundle -p:Version=$Version if ($LASTEXITCODE -ne 0) { throw "dotnet publish failed with exit code $LASTEXITCODE" } $required = @( @@ -38,23 +34,23 @@ $required = @( 'prompts\user-system.md', 'skills', 'README.md' ) foreach ($relative in $required) { - if (-not (Test-Path -LiteralPath (Join-Path $bundle $relative))) { throw "Release Bundle is missing $relative" } + if (-not (Test-Path -LiteralPath (Join-Path $stagingBundle $relative))) { throw "Release Bundle is missing $relative" } } foreach ($relative in @('agent.local.yaml', 'config\agent.local.example.yaml')) { - if (Test-Path -LiteralPath (Join-Path $bundle $relative)) { throw "Release Bundle must not contain local override input: $relative" } + if (Test-Path -LiteralPath (Join-Path $stagingBundle $relative)) { throw "Release Bundle must not contain local override input: $relative" } } -$manifestPath = Join-Path $bundle 'publish-manifest.sha256' -Get-ChildItem -LiteralPath $bundle -File -Recurse | +$manifestPath = Join-Path $stagingBundle 'publish-manifest.sha256' +Get-ChildItem -LiteralPath $stagingBundle -File -Recurse | Where-Object FullName -ne $manifestPath | Sort-Object FullName | ForEach-Object { - $relative = [IO.Path]::GetRelativePath($bundle, $_.FullName).Replace('\', '/') + $relative = [IO.Path]::GetRelativePath($stagingBundle, $_.FullName).Replace('\', '/') $hash = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant() "$hash $relative" } | Set-Content -LiteralPath $manifestPath -Encoding utf8NoBOM -Compress-Archive -LiteralPath $bundle -DestinationPath $zip -CompressionLevel Optimal +Compress-Archive -LiteralPath $stagingBundle -DestinationPath $zip -CompressionLevel Optimal $zipHash = (Get-FileHash -LiteralPath $zip -Algorithm SHA256).Hash.ToLowerInvariant() "$zipHash $([IO.Path]::GetFileName($zip))" | Set-Content -LiteralPath $checksum -Encoding ascii @@ -70,8 +66,8 @@ try { if (-not $SkipRuntimeCheck) { Push-Location $freshBundle try { - & .\agent-mcp.exe check --config .\agent.yaml --lang en - if ($LASTEXITCODE -ne 0) { throw "Bundle check failed with exit code $LASTEXITCODE. Run this script in an elevated terminal." } + & .\agent-mcp.exe sandbox resolve --config .\agent.yaml --lang en + if ($LASTEXITCODE -ne 0) { throw "Bundle resolution check failed with exit code $LASTEXITCODE." } } finally { Pop-Location } } @@ -80,6 +76,25 @@ finally { if (Test-Path -LiteralPath $freshRoot) { Remove-Item -LiteralPath $freshRoot -Recurse -Force } } +# The ZIP is reproducible defaults only. The deployment directory keeps explicitly local, +# publish-excluded inputs while all versioned defaults and binaries are replaced. +try { + if (Test-Path -LiteralPath $bundle) { + $resolvedBundle = (Resolve-Path -LiteralPath $bundle).Path + if (-not $resolvedBundle.StartsWith($outputRootPath + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { + throw 'Existing deployment Bundle escaped the validated output root.' + } + Get-ChildItem -LiteralPath $resolvedBundle -Force | + Where-Object Name -notin @('agent.local.yaml', 'local', 'logs', 'state') | + Remove-Item -Recurse -Force + } + else { New-Item -ItemType Directory -Path $bundle | Out-Null } + Copy-Item -Path (Join-Path $stagingBundle '*') -Destination $bundle -Recurse -Force +} +finally { + if (Test-Path -LiteralPath $stagingRoot) { Remove-Item -LiteralPath $stagingRoot -Recurse -Force } +} + Write-Output "Bundle: $bundle" Write-Output "ZIP: $zip" Write-Output "SHA-256: $checksum" -- cgit v1.2.3