Skip to main content

meerkat_comms/runtime/
comms_config.rs

1//! Core comms configuration types.
2
3#[cfg(not(target_arch = "wasm32"))]
4use crate::CommsConfig;
5use meerkat_core::CommsAuthMode;
6use serde::{Deserialize, Serialize};
7#[cfg(not(target_arch = "wasm32"))]
8use std::net::SocketAddr;
9#[cfg(not(target_arch = "wasm32"))]
10use std::path::{Path, PathBuf};
11
12/// Core configuration for agent-to-agent communication.
13///
14/// The `listen_tcp`/`listen_uds` addresses are for signed (CBOR+Ed25519)
15/// agent-to-agent communication. The `event_listen_tcp`/`event_listen_uds`
16/// addresses are for the plain-text external event listener (when `auth=Open`).
17///
18/// Both listeners can run simultaneously — the signed listener handles
19/// peer agents, while the plain listener accepts external events.
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
21pub struct CoreCommsConfig {
22    pub enabled: bool,
23    pub name: String,
24    /// Optional namespace for in-process registry isolation.
25    ///
26    /// Agents in different namespaces cannot see or send to each other via
27    /// `inproc://` unless they explicitly share this value.
28    pub inproc_namespace: Option<String>,
29    /// Address for signed (Ed25519) agent-to-agent listener.
30    #[cfg(not(target_arch = "wasm32"))]
31    pub listen_uds: Option<PathBuf>,
32    /// Address for signed (Ed25519) agent-to-agent listener.
33    #[cfg(not(target_arch = "wasm32"))]
34    pub listen_tcp: Option<SocketAddr>,
35    /// Runtime peer address advertised to other signed-comms participants.
36    ///
37    /// When absent, the runtime advertises its bound listener address. Set this
38    /// when binding to a wildcard/NAT/interface-local address that peers cannot
39    /// dial directly.
40    #[cfg(not(target_arch = "wasm32"))]
41    pub advertise_address: Option<String>,
42    /// Address for plain-text external event listener. Only active when `auth=Open`.
43    #[cfg(not(target_arch = "wasm32"))]
44    pub event_listen_tcp: Option<SocketAddr>,
45    /// Path for plain-text external event listener (UDS). Only active when `auth=Open`.
46    #[cfg(unix)]
47    pub event_listen_uds: Option<PathBuf>,
48    #[cfg(not(target_arch = "wasm32"))]
49    pub identity_dir: PathBuf,
50    #[cfg(not(target_arch = "wasm32"))]
51    pub trusted_peers_path: PathBuf,
52    pub ack_timeout_secs: u64,
53    pub max_message_bytes: u32,
54    pub auth: CommsAuthMode,
55    pub require_peer_auth: bool,
56    /// Allow binding plain event listener to non-loopback addresses.
57    /// This is a prompt injection vector — only enable with explicit intent.
58    pub allow_external_unauthenticated: bool,
59    /// Runtime-only pairing password for initial signed-comms enrollment.
60    #[serde(skip)]
61    pub pairing_password: Option<String>,
62}
63
64impl Default for CoreCommsConfig {
65    fn default() -> Self {
66        Self {
67            enabled: false,
68            name: "meerkat".to_string(),
69            inproc_namespace: None,
70            #[cfg(not(target_arch = "wasm32"))]
71            listen_uds: None,
72            #[cfg(not(target_arch = "wasm32"))]
73            listen_tcp: None,
74            #[cfg(not(target_arch = "wasm32"))]
75            advertise_address: None,
76            #[cfg(not(target_arch = "wasm32"))]
77            event_listen_tcp: None,
78            #[cfg(unix)]
79            event_listen_uds: None,
80            #[cfg(not(target_arch = "wasm32"))]
81            identity_dir: PathBuf::from(".rkat/identity"),
82            #[cfg(not(target_arch = "wasm32"))]
83            trusted_peers_path: PathBuf::from(".rkat/trusted_peers.json"),
84            ack_timeout_secs: 30,
85            max_message_bytes: 1_048_576,
86            auth: CommsAuthMode::default(),
87            require_peer_auth: true,
88            allow_external_unauthenticated: false,
89            pairing_password: None,
90        }
91    }
92}
93
94impl CoreCommsConfig {
95    pub fn with_name(name: &str) -> Self {
96        Self {
97            enabled: true,
98            name: name.to_string(),
99            ..Default::default()
100        }
101    }
102
103    #[cfg(not(target_arch = "wasm32"))]
104    fn interpolate_path(&self, path: &Path) -> PathBuf {
105        let path_str = path.to_string_lossy();
106        let interpolated = path_str.replace("{name}", &self.name);
107        PathBuf::from(interpolated)
108    }
109
110    #[cfg(not(target_arch = "wasm32"))]
111    pub fn resolve_paths(&self, base_dir: &Path) -> ResolvedCommsConfig {
112        let resolve = |path: &Path| -> PathBuf {
113            let interpolated = self.interpolate_path(path);
114            if interpolated.is_absolute() {
115                interpolated
116            } else {
117                base_dir.join(interpolated)
118            }
119        };
120
121        ResolvedCommsConfig {
122            enabled: self.enabled,
123            name: self.name.clone(),
124            inproc_namespace: self.inproc_namespace.clone(),
125            listen_uds: self.listen_uds.as_ref().map(|p| resolve(p)),
126            listen_tcp: self.listen_tcp,
127            advertise_address: self.advertise_address.clone(),
128            event_listen_tcp: self.event_listen_tcp,
129            #[cfg(unix)]
130            event_listen_uds: self.event_listen_uds.as_ref().map(|p| resolve(p)),
131            identity_dir: resolve(&self.identity_dir),
132            trusted_peers_path: resolve(&self.trusted_peers_path),
133            comms_config: CommsConfig {
134                ack_timeout_secs: self.ack_timeout_secs,
135                max_message_bytes: self.max_message_bytes,
136            },
137            auth: self.auth,
138            require_peer_auth: self.require_peer_auth,
139            allow_external_unauthenticated: self.allow_external_unauthenticated,
140            pairing_password: self.pairing_password.clone(),
141        }
142    }
143}
144
145/// Resolved comms configuration with absolute paths.
146#[cfg(not(target_arch = "wasm32"))]
147#[derive(Debug, Clone, PartialEq)]
148pub struct ResolvedCommsConfig {
149    pub enabled: bool,
150    pub name: String,
151    pub inproc_namespace: Option<String>,
152    /// Address for signed (Ed25519) agent-to-agent listener.
153    pub listen_uds: Option<PathBuf>,
154    /// Address for signed (Ed25519) agent-to-agent listener.
155    pub listen_tcp: Option<SocketAddr>,
156    /// Runtime peer address advertised to other signed-comms participants.
157    pub advertise_address: Option<String>,
158    /// Address for plain-text external event listener.
159    pub event_listen_tcp: Option<SocketAddr>,
160    /// Path for plain-text external event listener (UDS).
161    #[cfg(unix)]
162    pub event_listen_uds: Option<PathBuf>,
163    pub identity_dir: PathBuf,
164    pub trusted_peers_path: PathBuf,
165    pub comms_config: CommsConfig,
166    pub auth: CommsAuthMode,
167    pub require_peer_auth: bool,
168    pub allow_external_unauthenticated: bool,
169    pub pairing_password: Option<String>,
170}