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
+87 -2
View File
@@ -193,14 +193,99 @@ func stat(ctx context.Context, client rvboxv1.ControlClient, args []string, outp
return err
}
item := response.GetCommand()
renderCommandStat(output, item, time.Now().UTC())
return nil
}
// renderCommandStat keeps the human CLI useful when a caller does not have a
// protobuf-aware inspection tool. Durable lifecycle, expiry, retention, and
// Windows identity are rendered independently: a late terminal result must
// not erase the fact that the queue deadline was crossed.
func renderCommandStat(output io.Writer, item *rvboxv1.CommandRecord, now time.Time) {
if item == nil {
return
}
fmt.Fprintf(output, "command %s client=%s lifecycle=%s revision=%d events=%d\n", item.GetIssueUuid(), item.GetTargetClientId(), item.GetLifecycle(), item.GetCommandRevision(), item.GetLastEventSeq())
if item.GetQueueExpiryTime() != nil {
fmt.Fprintf(output, "queue_expiry=%s\n", item.GetQueueExpiryTime().AsTime().UTC().Format(time.RFC3339Nano))
expiry := item.GetQueueExpiryTime().AsTime().UTC()
fmt.Fprintf(output, "queue_expiry=%s\n", expiry.Format(time.RFC3339Nano))
if !now.IsZero() && !now.Before(expiry) {
fmt.Fprintln(output, "queue_expired=true")
}
}
if item.GetLateAfterExpiry() {
fmt.Fprintln(output, "late_after_expiry=true (terminal result arrived after queue expiry)")
}
if item.GetTerminalTime() != nil {
fmt.Fprintf(output, "terminal_time=%s\n", item.GetTerminalTime().AsTime().UTC().Format(time.RFC3339Nano))
}
return nil
if item.GetExitCode() != 0 || item.ExitCode != nil {
fmt.Fprintf(output, "exit_code=%d\n", item.GetExitCode())
}
if item.GetOutputTruncated() {
fmt.Fprintln(output, "output_truncated=true")
}
if item.GetOutputIncomplete() {
fmt.Fprintln(output, "output_incomplete=true")
}
if item.GetRetainedCompressedBytes() > 0 {
fmt.Fprintf(output, "retained_compressed_bytes=%d\n", item.GetRetainedCompressedBytes())
}
if rejection := item.GetRejection(); rejection != nil {
fmt.Fprintf(output, "rejection_code=%s rejection=%s\n", rejection.GetCode(), singleLine(rejection.GetMessage()))
}
if identity := item.GetWindowsExecutionIdentity(); identity != nil {
renderWindowsIdentity(output, item.GetSpec().GetElevated(), identity)
}
}
func renderWindowsIdentity(output io.Writer, requestedElevated bool, identity *rvboxv1.WindowsExecutionIdentity) {
fmt.Fprintf(output, "windows_requested_elevated=%t\n", requestedElevated)
if contexts := identity.GetAttemptedContexts(); len(contexts) > 0 {
names := make([]string, 0, len(contexts))
for _, context := range contexts {
names = append(names, windowsContextName(context))
}
fmt.Fprintf(output, "windows_attempted_contexts=%s\n", strings.Join(names, ","))
}
if identity.EffectiveContext != nil {
fmt.Fprintf(output, "windows_effective_context=%s\n", windowsContextName(identity.GetEffectiveContext()))
} else {
fmt.Fprintln(output, "windows_effective_context=none")
}
if identity.GetEffectiveUserSid() != "" {
fmt.Fprintf(output, "windows_effective_user_sid=%s\n", singleLine(identity.GetEffectiveUserSid()))
}
if identity.SessionId != nil {
fmt.Fprintf(output, "windows_session_id=%d\n", identity.GetSessionId())
}
if identity.GetSessionUserSid() != "" {
fmt.Fprintf(output, "windows_session_user_sid=%s\n", singleLine(identity.GetSessionUserSid()))
}
if identity.GetSelectionDetail() != "" {
fmt.Fprintf(output, "windows_selection_detail=%s\n", singleLine(identity.GetSelectionDetail()))
}
}
func windowsContextName(value rvboxv1.WindowsExecutionContext) string {
switch value {
case rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_LOCAL_SERVICE:
return "local-service"
case rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_LOCAL_SYSTEM:
return "local-system"
case rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_USER:
return "active-user"
case rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_USER_ELEVATED:
return "active-user-elevated"
case rvboxv1.WindowsExecutionContext_WINDOWS_EXECUTION_CONTEXT_ACTIVE_SYSTEM:
return "active-system"
default:
return "unspecified"
}
}
func singleLine(value string) string {
return strings.NewReplacer("\r", "\\r", "\n", "\\n", "\t", "\\t").Replace(value)
}
func runCommand(ctx context.Context, client rvboxv1.ControlClient, args []string, output, diagnostics io.Writer) error {