diff --git a/src/clients/openai.rs b/src/clients/openai.rs index 3bea007e..4a51543b 100644 --- a/src/clients/openai.rs +++ b/src/clients/openai.rs @@ -172,6 +172,7 @@ impl From for ChatCompletionsResponse { } #[derive(Debug, Default, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] pub struct ChatCompletionsRequest { /// A list of messages comprising the conversation so far. pub messages: Vec, @@ -290,6 +291,7 @@ pub struct ChatCompletionsRequest { /// Structure to contain parameters for detectors. #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] pub struct DetectorConfig { #[serde(skip_serializing_if = "Option::is_none")] pub input: Option>, @@ -398,6 +400,7 @@ pub enum Role { } #[derive(Debug, Default, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] pub struct Message { /// The role of the author of this message. pub role: Role, diff --git a/src/orchestrator/chat_completions_detection.rs b/src/orchestrator/chat_completions_detection.rs index 13519326..083ef977 100644 --- a/src/orchestrator/chat_completions_detection.rs +++ b/src/orchestrator/chat_completions_detection.rs @@ -396,8 +396,8 @@ mod tests { // Test to verify preprocess_chat_messages works correctly for multiple content type detectors // with single message in chat request - #[tokio::test] - async fn pretest_process_chat_messages_multiple_content_detector() { + #[test] + fn pretest_process_chat_messages_multiple_content_detector() { // Test setup let clients = ClientMap::new(); let detector_1_id = "detector1"; @@ -436,8 +436,8 @@ mod tests { // Test preprocess_chat_messages returns error correctly for multiple content type detectors // with incorrect message requirements - #[tokio::test] - async fn pretest_process_chat_messages_error_handling() { + #[test] + fn pretest_process_chat_messages_error_handling() { // Test setup let clients = ClientMap::new(); let detector_1_id = "detector1"; @@ -473,4 +473,87 @@ mod tests { "validation error: Last message role must be user, assistant, or system" ); } + // validate chat completions request with invalid fields + // (nonexistant fields or typos) + #[test] + fn test_validate() { + // Additional unknown field (additional_field) + let json_data = r#" + { + "messages": [ + { + "content": "this is a nice sentence", + "role": "user", + "name": "string" + } + ], + "model": "my_model", + "additional_field": "test", + "n": 1, + "temperature": 1, + "top_p": 1, + "user": "user-1234", + "detectors": { + "input": {} + } + } + "#; + let result: Result = serde_json::from_str(json_data); + assert!(result.is_err()); + let error = result.unwrap_err().to_string(); + assert!(error + .to_string() + .contains("unknown field `additional_field")); + + // Additional unknown field (additional_message") + let json_data = r#" + { + "messages": [ + { + "content": "this is a nice sentence", + "role": "user", + "name": "string", + "additional_msg: "test" + } + ], + "model": "my_model", + "n": 1, + "temperature": 1, + "top_p": 1, + "user": "user-1234", + "detectors": { + "input": {} + } + } + "#; + let result: Result = serde_json::from_str(json_data); + assert!(result.is_err()); + let error = result.unwrap_err().to_string(); + assert!(error.to_string().contains("unknown field `additional_msg")); + + // Additional unknown field (typo for input field in detectors) + let json_data = r#" + { + "messages": [ + { + "content": "this is a nice sentence", + "role": "user", + "name": "string" + } + ], + "model": "my_model", + "n": 1, + "temperature": 1, + "top_p": 1, + "user": "user-1234", + "detectors": { + "inputs": {} + } + } + "#; + let result: Result = serde_json::from_str(json_data); + assert!(result.is_err()); + let error = result.unwrap_err().to_string(); + assert!(error.to_string().contains("unknown field `inputs")); + } }