Files
aiturk-hermes-ide/apps/desktop/assets/codex-bridge/NativeWatchBootstrap.cs
T

90 lines
5.0 KiB
C#

// Thin Windows CLI_PATH executable. Runtime and original are owner-provisioned,
// absolute, SHA-pinned; never consult PATH or CODEX_CLI_PATH.
using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Threading;
using System.Runtime.InteropServices;
using System.Web.Script.Serialization;
class NativeWatchBootstrap {
// Assign this bootstrap BEFORE creating Python. Descendants inherit job
// membership atomically; the non-inheritable handle belongs only to us.
// Windows closes it even on TerminateProcess, killing Python and native.
static IntPtr ownedJob;
[StructLayout(LayoutKind.Sequential)] struct BasicLimits {
public long ProcessTime, JobTime;
public uint Flags;
public UIntPtr MinWorkingSet, MaxWorkingSet;
public uint ActiveProcesses;
public UIntPtr Affinity;
public uint Priority, Scheduling;
}
[StructLayout(LayoutKind.Sequential)] struct IoCounters {
public ulong ReadOps, WriteOps, OtherOps, ReadBytes, WriteBytes, OtherBytes;
}
[StructLayout(LayoutKind.Sequential)] struct ExtendedLimits {
public BasicLimits Basic;
public IoCounters Io;
public UIntPtr ProcessMemory, JobMemory, PeakProcessMemory, PeakJobMemory;
}
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
static extern IntPtr CreateJobObject(IntPtr attributes, string name);
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool SetInformationJobObject(IntPtr job, int kind, ref ExtendedLimits limits, uint size);
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
static void OwnProcessTree() {
ownedJob=CreateJobObject(IntPtr.Zero,null);
var limits=new ExtendedLimits(); limits.Basic.Flags=0x2000; // KILL_ON_JOB_CLOSE
if(ownedJob==IntPtr.Zero || !SetInformationJobObject(ownedJob,9,ref limits,(uint)Marshal.SizeOf(typeof(ExtendedLimits)))
|| !AssignProcessToJobObject(ownedJob,Process.GetCurrentProcess().Handle)) throw new Exception();
// Do not close here or in finally: the bootstrap is itself a member.
// The OS closes this handle at exit, preserving our native exit code.
}
static string Quote(string s) {
var b=new StringBuilder("\""); int slashes=0;
foreach(char c in s) {
if(c=='\\') {slashes++; continue;}
if(c=='"') { b.Append('\\',slashes*2+1); b.Append(c); }
else {b.Append('\\',slashes); b.Append(c);}
slashes=0;
}
b.Append('\\',slashes*2); b.Append('"'); return b.ToString();
}
static string Pin(Dictionary<string,object> c,string field) {
string p=(string)c[field], expected=(string)c[field+"_sha256"];
if(!Path.IsPathRooted(p) || String.Equals(Path.GetFullPath(p),Process.GetCurrentProcess().MainModule.FileName,StringComparison.OrdinalIgnoreCase)) throw new Exception();
using(var f=File.OpenRead(p)) using(var sha=SHA256.Create()) {
string actual=BitConverter.ToString(sha.ComputeHash(f)).Replace("-","").ToLowerInvariant();
if(actual!=expected.ToLowerInvariant()) throw new Exception();
}
return p;
}
static void Pump(Stream source, Stream target) {
byte[] buffer=new byte[8192]; int count;
while((count=source.Read(buffer,0,buffer.Length))>0) { target.Write(buffer,0,count); target.Flush(); }
}
static int Main(string[] args) {
try {
string manifest=Path.ChangeExtension(Process.GetCurrentProcess().MainModule.FileName,".json");
var c=new JavaScriptSerializer().Deserialize<Dictionary<string,object>>(File.ReadAllText(manifest));
string original=Pin(c,"original");
string python=Pin(c,"python");
string script=Pin(c,"script");
OwnProcessTree();
var argv=new List<string>{"-u",script,manifest}; argv.AddRange(args);
var quoted=new List<string>(); foreach(var a in argv) quoted.Add(Quote(a));
var p=Process.Start(new ProcessStartInfo(python,String.Join(" ",quoted.ToArray())) { UseShellExecute=false, CreateNoWindow=true, RedirectStandardInput=true, RedirectStandardOutput=true, RedirectStandardError=true });
var input=new Thread(()=> { try { Pump(Console.OpenStandardInput(),p.StandardInput.BaseStream); p.StandardInput.Close(); } catch(IOException) {} });
input.IsBackground=true; input.Start();
var output=new Thread(()=>Pump(p.StandardOutput.BaseStream,Console.OpenStandardOutput()));
var error=new Thread(()=>Pump(p.StandardError.BaseStream,Console.OpenStandardError()));
output.Start(); error.Start();
p.WaitForExit(); output.Join(); error.Join(); return p.ExitCode;
} catch { Console.Error.WriteLine("Owned native launcher integrity/configuration failure."); return 78; }
}
}