mirror of
https://github.com/openai/codex.git
synced 2026-10-31 19:28:49 +00:00
test(app-server-transport): cover expired pairing token
This commit is contained in:
@@ -16,6 +16,8 @@ const REMOTE_CONTROL_PAIRING_TIMEOUT: std::time::Duration = std::time::Duration:
|
|||||||
pub(super) struct RemoteControlPairingClient {
|
pub(super) struct RemoteControlPairingClient {
|
||||||
pairing_url: String,
|
pairing_url: String,
|
||||||
remote_control_token: String,
|
remote_control_token: String,
|
||||||
|
server_id: String,
|
||||||
|
environment_id: String,
|
||||||
expires_at: OffsetDateTime,
|
expires_at: OffsetDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,11 +25,15 @@ impl RemoteControlPairingClient {
|
|||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
remote_control_target: &RemoteControlTarget,
|
remote_control_target: &RemoteControlTarget,
|
||||||
remote_control_token: String,
|
remote_control_token: String,
|
||||||
|
server_id: String,
|
||||||
|
environment_id: String,
|
||||||
expires_at: OffsetDateTime,
|
expires_at: OffsetDateTime,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pairing_url: remote_control_target.pair_url.clone(),
|
pairing_url: remote_control_target.pair_url.clone(),
|
||||||
remote_control_token,
|
remote_control_token,
|
||||||
|
server_id,
|
||||||
|
environment_id,
|
||||||
expires_at,
|
expires_at,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +95,15 @@ impl RemoteControlPairingClient {
|
|||||||
environment_id,
|
environment_id,
|
||||||
expires_at,
|
expires_at,
|
||||||
} = pairing;
|
} = pairing;
|
||||||
let _ = server_id;
|
if server_id != self.server_id || environment_id != self.environment_id {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
format!(
|
||||||
|
"remote control pairing returned mismatched enrollment: expected server_id={}, environment_id={}; got server_id={}, environment_id={}",
|
||||||
|
self.server_id, self.environment_id, server_id, environment_id
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
let expires_at = OffsetDateTime::parse(&expires_at, &Rfc3339)
|
let expires_at = OffsetDateTime::parse(&expires_at, &Rfc3339)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ async fn start_remote_control_pairing_uses_server_token_and_maps_response() {
|
|||||||
pair_url,
|
pair_url,
|
||||||
},
|
},
|
||||||
"remote-control-token".to_string(),
|
"remote-control-token".to_string(),
|
||||||
|
"server-id".to_string(),
|
||||||
|
"environment-id".to_string(),
|
||||||
OffsetDateTime::from_unix_timestamp(33_336_362_096).expect("future timestamp should parse"),
|
OffsetDateTime::from_unix_timestamp(33_336_362_096).expect("future timestamp should parse"),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -168,6 +170,8 @@ async fn start_remote_control_pairing_preserves_backend_error_context() {
|
|||||||
pair_url,
|
pair_url,
|
||||||
},
|
},
|
||||||
"remote-control-token".to_string(),
|
"remote-control-token".to_string(),
|
||||||
|
"server-id".to_string(),
|
||||||
|
"environment-id".to_string(),
|
||||||
OffsetDateTime::from_unix_timestamp(33_336_362_096).expect("future timestamp should parse"),
|
OffsetDateTime::from_unix_timestamp(33_336_362_096).expect("future timestamp should parse"),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -184,3 +188,100 @@ async fn start_remote_control_pairing_preserves_backend_error_context() {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn start_remote_control_pairing_rejects_expired_server_token() {
|
||||||
|
let client = RemoteControlPairingClient::new(
|
||||||
|
&RemoteControlTarget {
|
||||||
|
websocket_url: "ws://unused".to_string(),
|
||||||
|
enroll_url: "http://unused".to_string(),
|
||||||
|
refresh_url: "http://unused".to_string(),
|
||||||
|
pair_url: "http://unused".to_string(),
|
||||||
|
},
|
||||||
|
"remote-control-token".to_string(),
|
||||||
|
"server-id".to_string(),
|
||||||
|
"environment-id".to_string(),
|
||||||
|
OffsetDateTime::from_unix_timestamp(0).expect("expired timestamp should parse"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let err = client
|
||||||
|
.start(StartRemoteControlPairingRequest { manual_code: false })
|
||||||
|
.await
|
||||||
|
.expect_err("expired server token should fail pairing");
|
||||||
|
|
||||||
|
assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput);
|
||||||
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
"remote control pairing is unavailable because the server token expired"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn start_remote_control_pairing_rejects_mismatched_enrollment() {
|
||||||
|
let listener = TcpListener::bind("127.0.0.1:0")
|
||||||
|
.await
|
||||||
|
.expect("listener should bind");
|
||||||
|
let pair_url = format!(
|
||||||
|
"http://{}/backend-api/wham/remote/control/server/pair",
|
||||||
|
listener.local_addr().expect("listener should have addr")
|
||||||
|
);
|
||||||
|
let server_task = tokio::spawn(async move {
|
||||||
|
let (stream, _) = listener.accept().await.expect("request should arrive");
|
||||||
|
let mut reader = BufReader::new(stream);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut line = String::new();
|
||||||
|
reader
|
||||||
|
.read_line(&mut line)
|
||||||
|
.await
|
||||||
|
.expect("request line should read");
|
||||||
|
if line == "\r\n" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = json!({
|
||||||
|
"pairing_code": "pairing-code",
|
||||||
|
"manual_pairing_code": null,
|
||||||
|
"server_id": "other-server-id",
|
||||||
|
"environment_id": "other-environment-id",
|
||||||
|
"expires_at": "3026-05-22T12:34:56Z",
|
||||||
|
})
|
||||||
|
.to_string();
|
||||||
|
reader
|
||||||
|
.get_mut()
|
||||||
|
.write_all(
|
||||||
|
format!(
|
||||||
|
"HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\n\r\n{response_body}",
|
||||||
|
response_body.len()
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("response should write");
|
||||||
|
});
|
||||||
|
let client = RemoteControlPairingClient::new(
|
||||||
|
&RemoteControlTarget {
|
||||||
|
websocket_url: "ws://unused".to_string(),
|
||||||
|
enroll_url: "http://unused".to_string(),
|
||||||
|
refresh_url: "http://unused".to_string(),
|
||||||
|
pair_url,
|
||||||
|
},
|
||||||
|
"remote-control-token".to_string(),
|
||||||
|
"server-id".to_string(),
|
||||||
|
"environment-id".to_string(),
|
||||||
|
OffsetDateTime::from_unix_timestamp(33_336_362_096).expect("future timestamp should parse"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let err = client
|
||||||
|
.start(StartRemoteControlPairingRequest { manual_code: false })
|
||||||
|
.await
|
||||||
|
.expect_err("mismatched enrollment should fail pairing");
|
||||||
|
server_task.await.expect("server task should finish");
|
||||||
|
|
||||||
|
assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
|
||||||
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
"remote control pairing returned mismatched enrollment: expected server_id=server-id, environment_id=environment-id; got server_id=other-server-id, environment_id=other-environment-id"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1504,9 +1504,14 @@ fn set_pairing_client(
|
|||||||
})?;
|
})?;
|
||||||
*pairing_client
|
*pairing_client
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(
|
.unwrap_or_else(std::sync::PoisonError::into_inner) =
|
||||||
RemoteControlPairingClient::new(remote_control_target, remote_control_token, expires_at),
|
Some(RemoteControlPairingClient::new(
|
||||||
);
|
remote_control_target,
|
||||||
|
remote_control_token,
|
||||||
|
enrollment.server_id.clone(),
|
||||||
|
enrollment.environment_id.clone(),
|
||||||
|
expires_at,
|
||||||
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user