microsandbox_protocol/exec_control.rs
1//! Optional host-only execution control, independent of the agent input byte stream.
2//!
3//! The relay adds this capability to its client-facing Ready payload only. It is never sent to
4//! agentd, persisted in snapshots, or part of the guest message inventory.
5
6use std::fmt;
7
8use serde::{Deserialize, Serialize};
9
10use crate::core::Ready;
11
12//--------------------------------------------------------------------------------------------------
13// Constants
14//--------------------------------------------------------------------------------------------------
15
16/// First host-only execution control contract.
17pub const EXEC_CONTROL_VERSION: u8 = 1;
18/// Framed host-control operation; requires the advertised capability and generation two.
19pub const EXEC_CONTROL_REQUEST: &str = "control.exec.signal";
20/// Physical-delivery result, distinct from an execution's terminal result.
21pub const EXEC_CONTROL_RESPONSE: &str = "control.exec.signal.result";
22
23//--------------------------------------------------------------------------------------------------
24// Types
25//--------------------------------------------------------------------------------------------------
26
27/// Ephemeral authority for the exact agent connection that received this advertisement.
28#[derive(Clone, Serialize, Deserialize)]
29pub struct ExecControlReady {
30 /// Supported host-only contract.
31 pub version: u8,
32 /// Existing local host-control endpoint, resolved by the runtime.
33 pub endpoint: String,
34 /// Random connection capability; invalidated on disconnect and never persisted.
35 pub connection: [u8; 16],
36}
37
38/// Client-facing Ready extension. Keeping this separate preserves existing Ready struct literals.
39#[derive(Serialize)]
40pub struct ExecControlAdvertisement<'a> {
41 /// Original guest capability payload, unchanged.
42 #[serde(flatten)]
43 pub ready: &'a Ready,
44 /// Host-owned route advertised to this one agent connection.
45 pub exec_control: &'a ExecControlReady,
46}
47
48/// Partial Ready reader that ignores unrelated guest capabilities.
49#[derive(Default, Deserialize)]
50pub struct ExecControlDiscovery {
51 /// Absence means that the existing agent path remains authoritative.
52 #[serde(default)]
53 pub exec_control: Option<ExecControlReady>,
54}
55
56/// One signal bound to a still-active agent connection and execution correlation.
57#[derive(Serialize, Deserialize)]
58pub struct ExecControlRequest {
59 /// Contract selected from the advertised capability.
60 pub version: u8,
61 /// Connection authority copied from the original Ready extension.
62 pub connection: [u8; 16],
63 /// Correlation allocated on that connection; never a raw guest PID.
64 pub id: u32,
65 /// Unix signal number.
66 pub signal: i32,
67}
68
69/// Acknowledges physical guest transport admission, not process exit or signal handling.
70#[derive(Debug, Serialize, Deserialize)]
71pub struct ExecControlResponse {
72 /// The complete signal frame reached the guest console transport.
73 pub delivered: bool,
74 /// Stable failure code, including uncertainty after admission.
75 pub error_code: Option<String>,
76 /// Non-sensitive delivery diagnostic.
77 pub error: Option<String>,
78}
79
80//--------------------------------------------------------------------------------------------------
81// Methods
82//--------------------------------------------------------------------------------------------------
83
84impl ExecControlResponse {
85 /// A complete physical write was observed.
86 pub fn delivered() -> Self {
87 Self {
88 delivered: true,
89 error_code: None,
90 error: None,
91 }
92 }
93
94 /// Reject or report delivery uncertainty without inventing an execution result.
95 pub fn error(code: &str, message: impl Into<String>) -> Self {
96 Self {
97 delivered: false,
98 error_code: Some(code.into()),
99 error: Some(message.into()),
100 }
101 }
102}
103
104//--------------------------------------------------------------------------------------------------
105// Trait Implementations
106//--------------------------------------------------------------------------------------------------
107
108impl fmt::Debug for ExecControlReady {
109 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
110 // Ready metadata is commonly logged. Never expose the connection authority there.
111 formatter
112 .debug_struct("ExecControlReady")
113 .field("version", &self.version)
114 .field("endpoint", &self.endpoint)
115 .field("connection", &"[redacted]")
116 .finish()
117 }
118}