feat: complete Windows client control and recovery paths

This commit is contained in:
2026-09-06 13:37:32 +00:00
parent 56b15c7f4f
commit 486894557d
38 changed files with 2188 additions and 106 deletions
@@ -35,12 +35,26 @@ var (
type NativeOptions struct {
Shells ShellPaths
WorkRoot string
JobProfiles map[string]JobProfile
MaxWrapperBytes uint64
MaxOutputChunk uint64
WindowsTermGrace time.Duration
Now func() time.Time
}
// JobProfile is the validated administrator policy for one protocol profile.
// The native Windows adapter applies only controls it can set and read back
// atomically on a Job Object; a requested unsupported required control rejects
// the command before any child is created.
type JobProfile struct {
RequiredControls []string
CPUPercent uint64
MemoryMaxBytes uint64
PIDsMax uint64
IOReadBPS uint64
IOWriteBPS uint64
}
func (options NativeOptions) withDefaults() NativeOptions {
if options.MaxWrapperBytes == 0 {
options.MaxWrapperBytes = 10 << 20
@@ -69,17 +83,19 @@ func newExecSupervisor(options NativeOptions) *execSupervisor {
}
type execProcess struct {
issue domain.UUID
identity supervisor.EffectiveIdentity
cmd *exec.Cmd
stdin io.WriteCloser
stdout io.ReadCloser
stderr io.ReadCloser
outputs chan outputResult
done chan struct{}
started time.Time
waitFn func() (int32, bool, error)
killFn func(uint32) error
issue domain.UUID
identity supervisor.EffectiveIdentity
cmd *exec.Cmd
pid uint32
stdin io.WriteCloser
stdout io.ReadCloser
stderr io.ReadCloser
outputs chan outputResult
done chan struct{}
started time.Time
waitFn func() (int32, bool, error)
killFn func(uint32) error
snapshotFn func() (supervisor.ResourceSnapshot, error)
mu sync.Mutex
finished bool
@@ -219,7 +235,7 @@ func (process *execProcess) startReaders(maxChunk uint64, remove func()) {
}
func materializeWrapper(directory string, wrapper Wrapper, now time.Time) (string, func(), error) {
if directory == "" || !now.IsZero() && now.Location() == nil {
if directory == "" {
return "", nil, ErrInvalidWorkingDirectory
}
if err := os.MkdirAll(directory, 0o700); err != nil {
@@ -441,7 +457,11 @@ func (manager *execSupervisor) startCommand(ctx context.Context, spec supervisor
}
func (manager *execSupervisor) registerProcess(issue domain.UUID, identity supervisor.EffectiveIdentity, command *exec.Cmd, stdin io.WriteCloser, stdout, stderr io.ReadCloser, started time.Time, waitFn func() (int32, bool, error), killFn func(uint32) error, cleanup func()) *execProcess {
process := &execProcess{issue: issue, identity: identity, cmd: command, stdin: stdin, stdout: stdout, stderr: stderr, outputs: make(chan outputResult, 32), done: make(chan struct{}), started: started, waitFn: waitFn, killFn: killFn}
var pid uint32
if command != nil && command.Process != nil && command.Process.Pid > 0 {
pid = uint32(command.Process.Pid)
}
process := &execProcess{issue: issue, identity: identity, cmd: command, pid: pid, stdin: stdin, stdout: stdout, stderr: stderr, outputs: make(chan outputResult, 32), done: make(chan struct{}), started: started, waitFn: waitFn, killFn: killFn}
manager.mu.Lock()
manager.active[issue] = process
manager.mu.Unlock()