mirror of
https://github.com/openai/codex.git
synced 2026-09-04 15:08:45 +00:00
test: cover Noise relay codec boundaries
Co-authored-by: Codex noreply@openai.com
This commit is contained in:
@@ -86,3 +86,7 @@ impl JsonRpcMessageDecoder {
|
||||
Ok(Some(message_len))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "message_framing_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
use codex_app_server_protocol::JSONRPCMessage;
|
||||
use codex_app_server_protocol::JSONRPCNotification;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::JsonRpcMessageDecoder;
|
||||
use super::MAX_NOISE_JSONRPC_MESSAGE_LEN;
|
||||
use super::NOISE_RECORD_PLAINTEXT_LEN;
|
||||
use super::frame_jsonrpc_message;
|
||||
use crate::ExecServerError;
|
||||
|
||||
#[test]
|
||||
fn fragments_and_reassembles_large_jsonrpc_message() {
|
||||
let message = JSONRPCMessage::Notification(JSONRPCNotification {
|
||||
method: "large/test".to_string(),
|
||||
params: Some(serde_json::json!({
|
||||
"data": "x".repeat(128 * 1024),
|
||||
})),
|
||||
});
|
||||
let framed = frame_jsonrpc_message(&message).unwrap();
|
||||
assert!(framed.len() > 128 * 1024);
|
||||
|
||||
let mut decoder = JsonRpcMessageDecoder::default();
|
||||
let mut decoded = Vec::new();
|
||||
for record in framed.chunks(NOISE_RECORD_PLAINTEXT_LEN) {
|
||||
decoded.extend(decoder.push(record).unwrap());
|
||||
}
|
||||
|
||||
assert_eq!(decoded, vec![message]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_declared_message_length_above_limit_without_payload() {
|
||||
let mut decoder = JsonRpcMessageDecoder::default();
|
||||
let declared_len = (MAX_NOISE_JSONRPC_MESSAGE_LEN as u32 + 1).to_be_bytes();
|
||||
|
||||
assert!(matches!(
|
||||
decoder.push(&declared_len),
|
||||
Err(ExecServerError::Protocol(message))
|
||||
if message == "Noise relay JSON-RPC message has invalid length"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_oversized_plaintext_record() {
|
||||
let mut decoder = JsonRpcMessageDecoder::default();
|
||||
|
||||
assert!(matches!(
|
||||
decoder.push(&vec![0; NOISE_RECORD_PLAINTEXT_LEN + 1]),
|
||||
Err(ExecServerError::Protocol(message))
|
||||
if message == "Noise relay plaintext record exceeds maximum length"
|
||||
));
|
||||
}
|
||||
@@ -6,6 +6,8 @@ use tokio_tungstenite::tungstenite::protocol::WebSocketConfig;
|
||||
|
||||
use crate::ExecServerError;
|
||||
|
||||
pub(crate) use harness::noise_harness_connection_from_websocket;
|
||||
|
||||
// This bounds allocation in tungstenite before protobuf and Noise record
|
||||
// validation run. It comfortably fits one maximum Noise record plus metadata.
|
||||
const MAX_NOISE_RELAY_WEBSOCKET_MESSAGE_SIZE: usize = 256 * 1024;
|
||||
|
||||
@@ -79,3 +79,7 @@ impl OrderedCiphertextFrames {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "ordered_ciphertext_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::MAX_PENDING_BYTES;
|
||||
use super::OrderedCiphertextFrames;
|
||||
|
||||
#[test]
|
||||
fn releases_ciphertexts_only_in_nonce_order() {
|
||||
let mut frames = OrderedCiphertextFrames::default();
|
||||
|
||||
assert_eq!(
|
||||
frames.push(/*seq*/ 1, b"second".to_vec()).unwrap(),
|
||||
Vec::<Vec<u8>>::new()
|
||||
);
|
||||
assert_eq!(
|
||||
frames.push(/*seq*/ 0, b"first".to_vec()).unwrap(),
|
||||
vec![b"first".to_vec(), b"second".to_vec()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_duplicate_ciphertexts_without_replacing_buffered_record() {
|
||||
let mut frames = OrderedCiphertextFrames::default();
|
||||
|
||||
assert_eq!(
|
||||
frames.push(/*seq*/ 1, b"first copy".to_vec()).unwrap(),
|
||||
Vec::<Vec<u8>>::new()
|
||||
);
|
||||
assert_eq!(
|
||||
frames.push(/*seq*/ 1, b"replacement".to_vec()).unwrap(),
|
||||
Vec::<Vec<u8>>::new()
|
||||
);
|
||||
assert_eq!(
|
||||
frames.push(/*seq*/ 0, b"zero".to_vec()).unwrap(),
|
||||
vec![b"zero".to_vec(), b"first copy".to_vec()]
|
||||
);
|
||||
assert_eq!(
|
||||
frames.push(/*seq*/ 0, b"duplicate".to_vec()).unwrap(),
|
||||
Vec::<Vec<u8>>::new()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_unbounded_reordering() {
|
||||
let mut frames = OrderedCiphertextFrames::default();
|
||||
|
||||
assert!(frames.push(/*seq*/ 65, Vec::new()).is_err());
|
||||
assert!(
|
||||
frames
|
||||
.push(/*seq*/ 1, vec![0; MAX_PENDING_BYTES + 1])
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user