Codex Handbook
exec-server/src/noise_relay/harness.rs 450 lines
//! Harness side of the Noise relay.//!//! The rendezvous service routes frames by `stream_id`, but does not authenticate//! the executor or see JSON-RPC plaintext. We claim a stream, complete hybrid IK//! against the registry-provided executor key, and then expose the result as a//! normal `JsonRpcConnection`. Outbound JSON-RPC is framed and split into Noise//! records; inbound records are reordered before decryption and reassembly.use futures::Sink;use futures::SinkExt;use futures::Stream;use futures::StreamExt;use tokio::sync::mpsc;use tokio::sync::watch;use tokio_tungstenite::tungstenite::Message;use tracing::Instrument;use tracing::debug;use tracing::info;use tracing::warn;use uuid::Uuid;use crate::ExecServerError;use crate::connection::CHANNEL_CAPACITY;use crate::connection::JsonRpcConnection;use crate::connection::JsonRpcConnectionEvent;use crate::connection::JsonRpcTransport;use crate::noise_channel::InitiatorHandshake;use crate::noise_channel::NoiseChannelIdentity;use crate::noise_channel::NoiseChannelPublicKey;use crate::noise_channel::NoiseTransport;use crate::noise_channel::noise_channel_prologue;use crate::noise_relay::message_framing::JsonRpcMessageDecoder;use crate::noise_relay::message_framing::NOISE_RECORD_PLAINTEXT_LEN;use crate::noise_relay::message_framing::frame_jsonrpc_message;use crate::noise_relay::ordered_ciphertext::OrderedCiphertextFrames;use crate::noise_relay::take_next_sequence;use crate::relay::RelayFrameBodyKind;use crate::relay::decode_relay_message_frame;use crate::relay::encode_relay_message_frame;use crate::relay_proto::RelayData;use crate::relay_proto::RelayMessageFrame;/// Values that bind one harness websocket to the intended executor registration.////// These fields all come from the same registry response. Keeping them together/// makes that relationship visible at the call site and avoids mixing up the/// several string and key arguments used to start the handshake.pub(crate) struct NoiseHarnessConnectionArgs {    pub(crate) connection_label: String,    pub(crate) environment_id: String,    pub(crate) executor_registration_id: String,    pub(crate) identity: NoiseChannelIdentity,    pub(crate) responder_public_key: NoiseChannelPublicKey,    pub(crate) harness_key_authorization: String,}// Reset frames are cleartext relay control and are not authenticated by Noise.// Preserve the availability signal while replacing attacker-controlled reason// text before it reaches disconnect diagnostics.const NOISE_RELAY_RESET_DISCONNECT_REASON: &str = "Noise relay stream reset";/// Adapt one harness rendezvous websocket into an authenticated JSON-RPC connection.////// The returned connection is not usable until the background task completes/// hybrid IK against the registry-pinned exec-server key. Rendezvous can see/// stream metadata and ciphertext, but never JSON-RPC plaintext or either/// endpoint's private key. Failures close the connection rather than falling/// back to plaintext.pub(crate) fn noise_harness_connection_from_websocket<T, E>(    stream: T,    args: NoiseHarnessConnectionArgs,) -> JsonRpcConnectionwhere    T: Sink<Message, Error = E> + Stream<Item = Result<Message, E>> + Unpin + Send + 'static,    E: std::fmt::Display + Send + 'static,{    let NoiseHarnessConnectionArgs {        connection_label,        environment_id,        executor_registration_id,        identity,        responder_public_key,        harness_key_authorization,    } = args;    let stream_id = Uuid::new_v4().to_string();    let (outgoing_tx, mut outgoing_rx) = mpsc::channel(CHANNEL_CAPACITY);    let (incoming_tx, incoming_rx) = mpsc::channel(CHANNEL_CAPACITY);    let (disconnected_tx, disconnected_rx) = watch::channel(false);    let stream_span = tracing::debug_span!(        "noise_relay.stream",        noise_side = "harness",        environment_id = %environment_id,        executor_registration_id = %executor_registration_id,        stream_id = %stream_id,    );    let websocket_task = tokio::spawn(async move {        let mut websocket = stream;        // Bind the Noise transcript to the exact environment registration and        // virtual relay stream before emitting any handshake bytes. A captured        // handshake cannot be spliced onto a different routed connection.        let prologue =            noise_channel_prologue(&environment_id, &executor_registration_id, &stream_id);        let (initiator_handshake, request) = match InitiatorHandshake::start(            &identity,            &responder_public_key,            &prologue,            harness_key_authorization.as_bytes(),        ) {            Ok(handshake) => handshake,            Err(error) => {                send_disconnected(                    &incoming_tx,                    &disconnected_tx,                    format!("failed to start Noise relay handshake: {error}"),                )                .await;                return;            }        };        // Resume claims the stream ID at rendezvous; Handshake carries the        // opaque first IK message. No JSON-RPC data is sent before the        // responder proves possession of the pinned static key.        let resume = RelayMessageFrame::resume(stream_id.clone());        let handshake = RelayMessageFrame::handshake(stream_id.clone(), request);        if websocket            .send(Message::Binary(encode_relay_message_frame(&resume).into()))            .await            .is_err()            || websocket                .send(Message::Binary(                    encode_relay_message_frame(&handshake).into(),                ))                .await                .is_err()        {            let _ = disconnected_tx.send(true);            return;        }        // During the handshake, ignore unrelated routed streams and control        // frames, but reject data on our stream. Accepting early data would        // create a plaintext or unauthenticated application path.        let mut transport = loop {            let Some(incoming_message) = websocket.next().await else {                send_disconnected(                    &incoming_tx,                    &disconnected_tx,                    "Noise relay websocket ended during handshake".to_string(),                )                .await;                return;            };            let message = match incoming_message {                Ok(Message::Binary(payload)) => payload,                Ok(Message::Close(_)) => {                    send_disconnected(                        &incoming_tx,                        &disconnected_tx,                        "Noise relay websocket received close frame during handshake".to_string(),                    )                    .await;                    return;                }                Ok(Message::Ping(_) | Message::Pong(_) | Message::Frame(_)) => continue,                Ok(Message::Text(_)) => {                    send_disconnected(                        &incoming_tx,                        &disconnected_tx,                        "Noise relay transport expects binary protobuf frames".to_string(),                    )                    .await;                    return;                }                Err(error) => {                    send_disconnected(                        &incoming_tx,                        &disconnected_tx,                        format!(                            "failed to read Noise relay websocket from {connection_label}: {error}"                        ),                    )                    .await;                    return;                }            };            let frame = match decode_relay_message_frame(message.as_ref()) {                Ok(frame) => frame,                Err(error) => {                    send_disconnected(                        &incoming_tx,                        &disconnected_tx,                        format!("failed to parse Noise relay frame: {error}"),                    )                    .await;                    return;                }            };            if frame.stream_id != stream_id {                debug!("Noise relay ignored frame for unrelated stream during handshake");                continue;            }            match frame.validate() {                Ok(RelayFrameBodyKind::Handshake) => {                    let response = match frame.into_handshake_payload() {                        Ok(response) => response,                        Err(error) => {                            send_disconnected(                                &incoming_tx,                                &disconnected_tx,                                format!("invalid Noise relay handshake response: {error}"),                            )                            .await;                            return;                        }                    };                    match initiator_handshake.finish(&response) {                        Ok(transport) => {                            info!(                                noise_event = "handshake",                                noise_outcome = "ok",                                "Noise harness handshake completed"                            );                            break transport;                        }                        Err(error) => {                            send_disconnected(                                &incoming_tx,                                &disconnected_tx,                                format!("Noise relay handshake failed: {error}"),                            )                            .await;                            return;                        }                    }                }                Ok(RelayFrameBodyKind::Reset) => {                    send_disconnected(                        &incoming_tx,                        &disconnected_tx,                        NOISE_RELAY_RESET_DISCONNECT_REASON.to_string(),                    )                    .await;                    return;                }                Ok(                    RelayFrameBodyKind::Ack                    | RelayFrameBodyKind::Resume                    | RelayFrameBodyKind::Heartbeat,                ) => {}                Ok(RelayFrameBodyKind::Data) | Err(_) => {                    send_disconnected(                        &incoming_tx,                        &disconnected_tx,                        "Noise relay received data before handshake completion".to_string(),                    )                    .await;                    return;                }            }        };        // After the handshake, each relay sequence maps to exactly one Noise        // transport record. Outbound records are encrypted once; inbound        // records are reordered and deduplicated before decryption.        let mut next_outbound_seq = 0u32;        let mut inbound_ciphertexts = OrderedCiphertextFrames::default();        let mut inbound_decoder = JsonRpcMessageDecoder::default();        'relay: loop {            tokio::select! {                maybe_message = outgoing_rx.recv() => {                    let Some(message) = maybe_message else {                        break;                    };                    let framed = match frame_jsonrpc_message(&message) {                        Ok(framed) => framed,                        Err(error) => {                            warn!("failed to frame JSON-RPC payload for Noise relay: {error}");                            break;                        }                    };                    for plaintext_record in framed.chunks(NOISE_RECORD_PLAINTEXT_LEN) {                        let seq = match take_next_sequence(&mut next_outbound_seq) {                            Ok(seq) => seq,                            Err(error) => {                                warn!("Noise relay sequence exhausted: {error}");                                break 'relay;                            }                        };                        let ciphertext = match transport.encrypt(plaintext_record) {                            Ok(ciphertext) => ciphertext,                            Err(error) => {                                warn!("failed to encrypt JSON-RPC payload for Noise relay: {error}");                                break 'relay;                            }                        };                        let frame = RelayMessageFrame::data(stream_id.clone(), seq, ciphertext);                        if let Err(error) = websocket                            .send(Message::Binary(encode_relay_message_frame(&frame).into()))                            .await                        {                            warn!("failed to write Noise relay websocket: {error}");                            break 'relay;                        }                    }                }                incoming_message = websocket.next() => {                    let Some(incoming_message) = incoming_message else {                        break;                    };                    match incoming_message {                        Ok(Message::Binary(payload)) => {                            let frame = match decode_relay_message_frame(payload.as_ref()) {                                Ok(frame) => frame,                                Err(error) => {                                    send_malformed(&incoming_tx, error.to_string()).await;                                    break;                                }                            };                            if frame.stream_id != stream_id {                                continue;                            }                            match frame.validate() {                                Ok(RelayFrameBodyKind::Data) => {                                    let data = match frame.into_data() {                                        Ok(data) => data,                                        Err(error) => {                                            send_malformed(&incoming_tx, error.to_string()).await;                                            break;                                        }                                    };                                    if let Err(error) = receive_data(                                        &mut inbound_ciphertexts,                                        &mut transport,                                        &mut inbound_decoder,                                        data,                                        &incoming_tx,                                    )                                    .await                                    {                                        send_malformed(&incoming_tx, error.to_string()).await;                                        break;                                    }                                }                                Ok(RelayFrameBodyKind::Reset) => {                                    let _ = incoming_tx                                        .send(JsonRpcConnectionEvent::Disconnected {                                            reason: Some(                                                NOISE_RELAY_RESET_DISCONNECT_REASON.to_string(),                                            ),                                        })                                        .await;                                    break;                                }                                Ok(                                    RelayFrameBodyKind::Ack                                    | RelayFrameBodyKind::Resume                                    | RelayFrameBodyKind::Heartbeat,                                ) => {}                                Ok(RelayFrameBodyKind::Handshake) | Err(_) => {                                    send_malformed(                                        &incoming_tx,                                        "Noise relay received invalid post-handshake frame".to_string(),                                    )                                    .await;                                    break;                                }                            }                        }                        Ok(Message::Close(_)) => break,                        Ok(Message::Ping(_) | Message::Pong(_) | Message::Frame(_)) => {}                        Ok(Message::Text(_)) => {                            send_malformed(                                &incoming_tx,                                "Noise relay transport expects binary protobuf frames".to_string(),                            )                            .await;                            break;                        }                        Err(error) => {                            debug!("Noise relay websocket read failed: {error}");                            break;                        }                    }                }            }        }        let _ = disconnected_tx.send(true);    }    .instrument(stream_span));    JsonRpcConnection {        outgoing_tx,        incoming_rx,        disconnected_rx,        task_handles: vec![websocket_task],        transport: JsonRpcTransport::Plain,    }}/// Order and decrypt one relay frame, then emit any complete JSON-RPC messages./// Relay records and JSON-RPC messages do not share boundaries, so reassembly/// happens after decryption.async fn receive_data(    inbound_ciphertexts: &mut OrderedCiphertextFrames,    transport: &mut NoiseTransport,    decoder: &mut JsonRpcMessageDecoder,    data: RelayData,    incoming_tx: &mpsc::Sender<JsonRpcConnectionEvent>,) -> Result<(), ExecServerError> {    // Ordering must happen before decryption because Noise transport nonces are    // implicit. A future or duplicate ciphertext passed directly to Clatter    // would desynchronize the channel.    for ciphertext in inbound_ciphertexts.push(data.seq, data.payload)? {        let plaintext = transport.decrypt(&ciphertext).map_err(|error| {            ExecServerError::Protocol(format!("Noise relay decryption failed: {error}"))        })?;        // The authenticated byte stream can carry partial or multiple JSON-RPC        // messages; emit only complete, successfully parsed messages.        for message in decoder.push(&plaintext)? {            incoming_tx                .send(JsonRpcConnectionEvent::Message(message))                .await                .map_err(|_| ExecServerError::Closed)?;        }    }    Ok(())}async fn send_malformed(incoming_tx: &mpsc::Sender<JsonRpcConnectionEvent>, reason: String) {    let _ = incoming_tx        .send(JsonRpcConnectionEvent::MalformedMessage { reason })        .await;}async fn send_disconnected(    incoming_tx: &mpsc::Sender<JsonRpcConnectionEvent>,    disconnected_tx: &watch::Sender<bool>,    reason: String,) {    let _ = disconnected_tx.send(true);    let _ = incoming_tx        .send(JsonRpcConnectionEvent::Disconnected {            reason: Some(reason),        })        .await;}