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
+32 -4
View File
@@ -50,6 +50,7 @@ type EventAppend struct {
ImmutableSHA256 [32]byte
Lifecycle *rvboxv1.CommandLifecycle
LifecycleRevision uint64
WindowsIdentity *rvboxv1.WindowsExecutionIdentity
Output bool
UseCloseout bool
}
@@ -79,6 +80,16 @@ func (store *Store) AppendCommandEvent(ctx context.Context, event EventAppend) (
if err != nil {
return result, err
}
var windowsIdentity []byte
if event.WindowsIdentity != nil {
if len(event.WindowsIdentity.GetAttemptedContexts()) > 8 || len(event.WindowsIdentity.GetSelectionDetail()) > 4096 {
return result, ErrInvalidSegmentRecord
}
windowsIdentity, err = proto.MarshalOptions{Deterministic: true}.Marshal(event.WindowsIdentity)
if err != nil || len(windowsIdentity) > 16<<10 {
return result, ErrInvalidSegmentRecord
}
}
store.writeMu.Lock()
defer store.writeMu.Unlock()
@@ -89,10 +100,13 @@ func (store *Store) AppendCommandEvent(ctx context.Context, event EventAppend) (
var lastSequence, commandOutputCharged, commandCharged, clientCharged, serverCharged, closeoutRemaining uint64
var currentLifecycle uint32
var currentRevision uint64
var lateAfterExpiry int
var queueExpiry sql.NullInt64
var clientID string
query := `SELECT commands.last_event_seq, commands.output_charged_bytes,
commands.charged_bytes, commands.closeout_remaining_bytes, commands.client_id, clients.charged_bytes,
storage_counters.command_charged_bytes, commands.lifecycle, commands.revision
storage_counters.command_charged_bytes, commands.lifecycle, commands.revision,
commands.queue_expiry_time, commands.late_after_expiry
FROM commands JOIN clients ON clients.client_id = commands.client_id
JOIN storage_counters ON storage_counters.singleton = 1 WHERE commands.issue_uuid = ?`
arguments := []any{event.IssueUUID[:]}
@@ -105,7 +119,7 @@ JOIN storage_counters ON storage_counters.singleton = 1 WHERE commands.issue_uui
arguments = append(arguments, event.SessionGeneration)
}
err = database.QueryRowContext(ctx, query, arguments...).Scan(
&lastSequence, &commandOutputCharged, &commandCharged, &closeoutRemaining, &clientID, &clientCharged, &serverCharged, &currentLifecycle, &currentRevision)
&lastSequence, &commandOutputCharged, &commandCharged, &closeoutRemaining, &clientID, &clientCharged, &serverCharged, &currentLifecycle, &currentRevision, &queueExpiry, &lateAfterExpiry)
if errors.Is(err, sql.ErrNoRows) {
return result, ErrCommandNotFound
}
@@ -133,6 +147,11 @@ JOIN storage_counters ON storage_counters.singleton = 1 WHERE commands.issue_uui
return result, domain.ValidateTransition(rvboxv1.CommandLifecycle(currentLifecycle), *event.Lifecycle)
}
}
late := queueExpiry.Valid && event.ReceiptUnixNano >= queueExpiry.Int64
lateValue := 0
if late {
lateValue = 1
}
rowsCharged, indexesCharged := uint64(1), uint64(1)
if store.willCreateSegment(event.IssueUUID, uint64(len(encoded))) {
rowsCharged++
@@ -215,8 +234,12 @@ payload, segment_ordinal, segment_record_offset, segment_record_length, immutabl
var update sql.Result
commandUpdate := `UPDATE commands SET last_event_seq = ?,
retained_compressed_bytes = retained_compressed_bytes + ?, output_charged_bytes = ?, charged_bytes = ?,
closeout_remaining_bytes = ?`
commandArgs := []any{event.EventSeq, len(event.Payload), reservation.CommandOutputCharged, reservation.CommandTotalCharged, reservation.CloseoutRemaining}
closeout_remaining_bytes = ?, late_after_expiry = CASE WHEN ? = 1 THEN 1 ELSE late_after_expiry END`
commandArgs := []any{event.EventSeq, len(event.Payload), reservation.CommandOutputCharged, reservation.CommandTotalCharged, reservation.CloseoutRemaining, lateValue}
if event.WindowsIdentity != nil {
commandUpdate = `UPDATE commands SET windows_execution_identity = ?, ` + commandUpdate[len("UPDATE commands SET "):]
commandArgs = append([]any{windowsIdentity}, commandArgs...)
}
if event.Lifecycle != nil {
terminal := 0
if domain.IsTerminal(*event.Lifecycle) {
@@ -236,6 +259,11 @@ retained_compressed_bytes = retained_compressed_bytes + ?, output_charged_bytes
}
}
}
if err == nil && late && lateAfterExpiry == 0 {
if err = appendLateExpiryAudit(ctx, tx, event.ReceiptUnixNano, clientID, event.IssueUUID, event.ReceiptUnixNano); err == nil {
lateAfterExpiry = 1
}
}
if err == nil && event.EventType == 7 {
// Stdin acknowledgements are command events, but their durable delivery
// cursor lives in stdin_writes. Mark the cumulative prefix in the same