feat: complete Windows client control and recovery paths
This commit is contained in:
@@ -17,6 +17,29 @@ var (
|
||||
ErrUnsupported = errors.New("supervisor operation is unsupported")
|
||||
)
|
||||
|
||||
// StartError carries durable context-selection evidence when a command is
|
||||
// rejected before a process exists. The runtime records the evidence with
|
||||
// the rejection event without treating the error as a second public protocol
|
||||
// type. Unwrap keeps ordinary retry/error classification working.
|
||||
type StartError struct {
|
||||
Cause error
|
||||
WindowsIdentity *rvboxv1.WindowsExecutionIdentity
|
||||
}
|
||||
|
||||
func (err *StartError) Error() string {
|
||||
if err == nil || err.Cause == nil {
|
||||
return "supervisor start failed"
|
||||
}
|
||||
return err.Cause.Error()
|
||||
}
|
||||
|
||||
func (err *StartError) Unwrap() error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return err.Cause
|
||||
}
|
||||
|
||||
type SignalKind uint8
|
||||
|
||||
const (
|
||||
@@ -53,12 +76,55 @@ func (spec StartSpec) Validate() error {
|
||||
// EffectiveIdentity is immutable process evidence captured before launch.
|
||||
// Empty user/session fields mean a Session 0 service context.
|
||||
type EffectiveIdentity struct {
|
||||
Context string
|
||||
SessionID uint32
|
||||
UserSID string
|
||||
LogonSID string
|
||||
Elevated bool
|
||||
Integrity string
|
||||
Context string
|
||||
SessionID uint32
|
||||
SessionUserSID string
|
||||
UserSID string
|
||||
LogonSID string
|
||||
Elevated bool
|
||||
Integrity string
|
||||
AttemptedContexts []string
|
||||
SelectionDetail string
|
||||
}
|
||||
|
||||
// WindowsIdentity converts the platform-neutral evidence to the public
|
||||
// immutable status/event shape. Unknown contexts are deliberately omitted so
|
||||
// the portable test supervisor never pretends to be a Windows launch.
|
||||
func (identity EffectiveIdentity) WindowsIdentity() *rvboxv1.WindowsExecutionIdentity {
|
||||
result := &rvboxv1.WindowsExecutionIdentity{SessionUserSid: identity.SessionUserSID, EffectiveUserSid: identity.UserSID, SelectionDetail: identity.SelectionDetail}
|
||||
for _, contextName := range identity.AttemptedContexts {
|
||||
if context, ok := windowsExecutionContext(contextName); ok {
|
||||
result.AttemptedContexts = append(result.AttemptedContexts, context)
|
||||
}
|
||||
}
|
||||
if context, ok := windowsExecutionContext(identity.Context); ok {
|
||||
result.EffectiveContext = &context
|
||||
if context == rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_USER || context == rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_USER_ELEVATED || context == rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_SYSTEM {
|
||||
session := identity.SessionID
|
||||
result.SessionId = &session
|
||||
}
|
||||
}
|
||||
if result.EffectiveContext == nil && len(result.AttemptedContexts) == 0 && result.SelectionDetail == "" && result.SessionUserSid == "" && result.EffectiveUserSid == "" {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func windowsExecutionContext(value string) (rvboxv1.WindowsExecutionContext, bool) {
|
||||
switch value {
|
||||
case "LOCAL_SERVICE":
|
||||
return rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_LOCAL_SERVICE, true
|
||||
case "LOCAL_SYSTEM":
|
||||
return rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_LOCAL_SYSTEM, true
|
||||
case "ACTIVE_USER":
|
||||
return rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_USER, true
|
||||
case "ACTIVE_USER_ELEVATED":
|
||||
return rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_USER_ELEVATED, true
|
||||
case "ACTIVE_SYSTEM":
|
||||
return rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_SYSTEM, true
|
||||
default:
|
||||
return rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_UNSPECIFIED, false
|
||||
}
|
||||
}
|
||||
|
||||
type Process interface {
|
||||
|
||||
Reference in New Issue
Block a user