summaryrefslogtreecommitdiff
path: root/scripts/Publish-Release.ps1
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-08-12 05:44:54 +0900
committertanaka takashi <isazaka@gmail.com>2026-08-12 05:44:54 +0900
commitb56614c814b904c224315a11f9686f0d47abd3d3 (patch)
treee6ae4feb852ea4492bf947eabba1e11ab157686a /scripts/Publish-Release.ps1
parent98b6a2aeedd591058c1d81e401d24f3ded162926 (diff)
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.
Diffstat (limited to 'scripts/Publish-Release.ps1')
-rw-r--r--scripts/Publish-Release.ps147
1 files changed, 31 insertions, 16 deletions
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"