Public release release-98d969b26488

Source commit: 98d969b26488b4cda8b2381fa870276a00ca98ea

Public tree identity: sha256:d02dd1e8d3547a489bb300741bed544bdc60bb8fe0bd541fd43ce9bfa7129a3e
This commit is contained in:
Clusterflux release 2026-07-16 15:49:35 +02:00
commit 8ded2b6a42
210 changed files with 76954 additions and 0 deletions

View file

@ -0,0 +1,200 @@
use std::io::{BufRead, BufReader, Write};
use std::net::{SocketAddr, TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use super::{CoordinatorRequest, CoordinatorResponse, CoordinatorService, CoordinatorServiceError};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ClientAuthorityMode {
Strict,
LocalTrustedLoopback,
}
impl CoordinatorService {
pub fn serve_tcp(self, listener: TcpListener) -> Result<(), CoordinatorServiceError> {
if !listener.local_addr()?.ip().is_loopback() {
return Err(CoordinatorServiceError::Protocol(
"the native coordinator transport is plaintext and restricted to loopback; expose a remote coordinator only through a secure transport"
.to_owned(),
));
}
self.serve_tcp_with_authority(listener, ClientAuthorityMode::Strict)
}
pub fn serve_tcp_local_trusted(
self,
listener: TcpListener,
) -> Result<(), CoordinatorServiceError> {
if !listener.local_addr()?.ip().is_loopback() {
return Err(CoordinatorServiceError::Protocol(
"local trusted request mode is restricted to a loopback listener".to_owned(),
));
}
self.serve_tcp_with_authority(listener, ClientAuthorityMode::LocalTrustedLoopback)
}
fn serve_tcp_with_authority(
self,
listener: TcpListener,
authority_mode: ClientAuthorityMode,
) -> Result<(), CoordinatorServiceError> {
let shared = Arc::new(Mutex::new(self));
for stream in listener.incoming() {
let stream = stream?;
let service = Arc::clone(&shared);
std::thread::spawn(move || {
if let Err(err) = handle_shared_stream(service, stream, authority_mode) {
eprintln!("coordinator stream failed: {err}");
}
});
}
Ok(())
}
pub fn handle_stream(&mut self, stream: TcpStream) -> Result<(), CoordinatorServiceError> {
self.handle_stream_with_authority(stream, ClientAuthorityMode::Strict)
}
#[cfg(test)]
pub(super) fn handle_stream_local_trusted(
&mut self,
stream: TcpStream,
) -> Result<(), CoordinatorServiceError> {
self.handle_stream_with_authority(stream, ClientAuthorityMode::LocalTrustedLoopback)
}
fn handle_stream_with_authority(
&mut self,
stream: TcpStream,
authority_mode: ClientAuthorityMode,
) -> Result<(), CoordinatorServiceError> {
let mut reader = BufReader::new(stream.try_clone()?);
let mut writer = stream;
loop {
let mut line = String::new();
if reader.read_line(&mut line)? == 0 {
return Ok(());
}
if line.trim().is_empty() {
continue;
}
let response = match decode_wire_request(&line) {
Ok(request) => match authorize_client_request(&request, authority_mode)
.and_then(|()| self.handle_request(request))
{
Ok(response) => response,
Err(err) => CoordinatorResponse::Error {
message: err.to_string(),
},
},
Err(err) => CoordinatorResponse::Error {
message: err.to_string(),
},
};
serde_json::to_writer(&mut writer, &response)?;
writer.write_all(b"\n")?;
writer.flush()?;
}
}
}
fn handle_shared_stream(
service: Arc<Mutex<CoordinatorService>>,
stream: TcpStream,
authority_mode: ClientAuthorityMode,
) -> Result<(), CoordinatorServiceError> {
let mut reader = BufReader::new(stream.try_clone()?);
let mut writer = stream;
loop {
let mut line = String::new();
if reader.read_line(&mut line)? == 0 {
return Ok(());
}
if line.trim().is_empty() {
continue;
}
let response = match decode_wire_request(&line) {
Ok(request) => match authorize_client_request(&request, authority_mode) {
Ok(()) => match service.lock() {
Ok(mut service) => match service.handle_request(request) {
Ok(response) => response,
Err(err) => CoordinatorResponse::Error {
message: err.to_string(),
},
},
Err(_) => CoordinatorResponse::Error {
message: "coordinator service lock poisoned".to_owned(),
},
},
Err(err) => CoordinatorResponse::Error {
message: err.to_string(),
},
},
Err(err) => CoordinatorResponse::Error {
message: err.to_string(),
},
};
serde_json::to_writer(&mut writer, &response)?;
writer.write_all(b"\n")?;
writer.flush()?;
}
}
pub fn bind_listener(addr: &str) -> Result<(TcpListener, SocketAddr), CoordinatorServiceError> {
let listener = TcpListener::bind(addr)?;
let addr = listener.local_addr()?;
Ok((listener, addr))
}
fn decode_wire_request(line: &str) -> Result<CoordinatorRequest, CoordinatorServiceError> {
serde_json::from_str::<super::CoordinatorWireRequest>(line)?
.into_request()
.map_err(CoordinatorServiceError::Protocol)
}
fn authorize_client_request(
request: &CoordinatorRequest,
authority_mode: ClientAuthorityMode,
) -> Result<(), CoordinatorServiceError> {
if authority_mode == ClientAuthorityMode::LocalTrustedLoopback {
return Ok(());
}
match request {
CoordinatorRequest::Ping
| CoordinatorRequest::Authenticated { .. }
| CoordinatorRequest::ExchangeNodeEnrollmentGrant { .. }
| CoordinatorRequest::SignedNode { .. }
| CoordinatorRequest::NodeHeartbeat {
node_signature: Some(_),
..
}
| CoordinatorRequest::StartProcess {
actor_agent: Some(_),
agent_signature: Some(_),
..
}
| CoordinatorRequest::LaunchTask {
actor_agent: Some(_),
agent_signature: Some(_),
..
}
| CoordinatorRequest::AdminStatus { .. }
| CoordinatorRequest::SuspendTenant { .. } => Ok(()),
_ => Err(CoordinatorServiceError::Protocol(
"strict Core Client authority requires an authenticated CLI session, signed Agent, signed Node, enrollment grant exchange, or admin credential; request-body identity fields are not authority"
.to_owned(),
)),
}
}
#[cfg(test)]
mod transport_boundary_tests {
use super::*;
#[test]
fn native_plaintext_service_refuses_non_loopback_listener() {
let (listener, _) = bind_listener("0.0.0.0:0").unwrap();
let error = CoordinatorService::new(1).serve_tcp(listener).unwrap_err();
assert!(error.to_string().contains("restricted to loopback"));
}
}