bb0975f93b
Removed: - The \ and \ variables - The 'app-data dir' phrase in the .DESCRIPTION docstring - The 'app-data dir' phrase in step 2's comment The Tier 2 clone is the only allowed directory; AppData is enforced off-limits by the agent's *AppData\\\\* bash deny rule (no OS-level ACL needed since the agent's bash commands are denied at the OpenCode permission layer). Per the user's 2026-06-18 'NEVER USE APPDATA' directive. Refs: conductor/tracks/tier2_no_appdata_20260618
101 lines
3.3 KiB
PowerShell
101 lines
3.3 KiB
PowerShell
# scripts/tier2/run_tier2_sandboxed.ps1
|
|
<#
|
|
.SYNOPSIS
|
|
Launch OpenCode in the Tier 2 sandboxed mode.
|
|
.DESCRIPTION
|
|
Acquires a Windows restricted token (drops dangerous privileges),
|
|
wraps the process tree in a Job Object, and launches OpenCode + the
|
|
MCP server under the restricted token. The Tier 2 clone at
|
|
C:\projects\manual_slop_tier2\ is the only directory the OpenCode
|
|
session can read/write; AppData is OFF-LIMITS (enforced by the
|
|
agent's *AppData\\* bash deny rule).
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$Tier2ClonePath = "C:\projects\manual_slop_tier2",
|
|
[string]$MainRepoPath = "C:\projects\manual_slop"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$Tier2ClonePath = (Resolve-Path $Tier2ClonePath).Path
|
|
$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
|
|
# (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
|