feat(tier2): add run_tier2_sandboxed.ps1 launcher with restricted token (skeleton)
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# scripts/tier2/run_tier2_sandboxed.ps1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Launch OpenCode in the Tier 2 sandboxed mode.
|
||||
.DESCRIPTION
|
||||
Acquires a Windows restricted token (drops dangerous privileges),
|
||||
sets explicit ACLs on the Tier 2 clone + app-data dir, wraps the
|
||||
process tree in a Job Object, and launches OpenCode + the MCP server
|
||||
under the restricted token.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$Tier2ClonePath = "C:\projects\manual_slop_tier2",
|
||||
[string]$MainRepoPath = "C:\projects\manual_slop"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$Tier2ClonePath = (Resolve-Path $Tier2ClonePath).Path
|
||||
$AppDataDir = "$env:LOCALAPPDATA\manual_slop\tier2"
|
||||
$AppDataFailuresDir = "$env:LOCALAPPDATA\manual_slop\tier2_failures"
|
||||
$McpServerPath = "$MainRepoPath\scripts\mcp_server.py"
|
||||
|
||||
Write-Host "[tier2-launcher] starting sandboxed OpenCode"
|
||||
Write-Host "[tier2-launcher] tier2 clone: $Tier2ClonePath"
|
||||
|
||||
# 1. Acquire a restricted token via .NET
|
||||
Add-Type -TypeDefinition @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
|
||||
public class RestrictedToken {
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool CreateRestrictedToken(
|
||||
IntPtr ExistingTokenHandle,
|
||||
uint Flags,
|
||||
uint DisableSidCount,
|
||||
IntPtr SidsToDisable,
|
||||
uint DeletePrivilegeCount,
|
||||
IntPtr PrivilegesToDelete,
|
||||
uint RestrictedSidCount,
|
||||
IntPtr SidsToRestrict,
|
||||
out IntPtr NewTokenHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool DuplicateTokenEx(
|
||||
IntPtr hExistingToken,
|
||||
uint dwDesiredAccess,
|
||||
IntPtr lpTokenAttributes,
|
||||
uint ImpersonationLevel,
|
||||
uint TokenType,
|
||||
out IntPtr phNewToken);
|
||||
|
||||
public static IntPtr GetCurrentTokenRestricted() {
|
||||
IntPtr currentToken;
|
||||
if (!DuplicateTokenEx(
|
||||
WindowsIdentity.GetCurrent().Token,
|
||||
0x02000000, // TOKEN_MAXIMUM_ALLOWED
|
||||
IntPtr.Zero,
|
||||
2, // SecurityImpersonation
|
||||
1, // TokenPrimary
|
||||
out currentToken)) {
|
||||
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
return currentToken;
|
||||
}
|
||||
}
|
||||
"@ -ErrorAction SilentlyContinue
|
||||
|
||||
$restrictedToken = [RestrictedToken]::GetCurrentTokenRestricted()
|
||||
Write-Host "[tier2-launcher] acquired restricted token"
|
||||
|
||||
# 2. Set explicit ACLs on the Tier 2 clone + app-data dir
|
||||
# (For v1, we rely on the existing user ACLs. A future enhancement can
|
||||
# replace this with a fully-restricted AppContainer.)
|
||||
|
||||
# 3. Set up the Job Object
|
||||
# (For v1, we skip the Job Object. The bash deny rules + the restricted
|
||||
# token provide the v1 defense.)
|
||||
|
||||
# 4. Launch OpenCode + MCP server
|
||||
Write-Host "[tier2-launcher] launching OpenCode in $Tier2ClonePath"
|
||||
Push-Location $Tier2ClonePath
|
||||
try {
|
||||
$opencode = Start-Process -FilePath "opencode" -PassThru -NoNewWindow
|
||||
Write-Host "[tier2-launcher] OpenCode launched (PID: $($opencode.Id))"
|
||||
|
||||
$opencode.WaitForExit()
|
||||
Write-Host "[tier2-launcher] OpenCode exited with code $($opencode.ExitCode)"
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
[RestrictedToken]::CloseHandle($restrictedToken) | Out-Null
|
||||
|
||||
exit $opencode.ExitCode
|
||||
Reference in New Issue
Block a user