# 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
