pub use crate::privilege::DeviceClass;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrivilegeSeverity {
None,
Elevated,
Root,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PrivilegeRequirement {
None,
PrivilegedPort(u16),
RawSockets,
PacketCapture,
DeviceAccess(DeviceClass),
Root,
}
impl PrivilegeRequirement {
pub fn description(&self) -> String {
match self {
Self::None => "None".to_string(),
Self::PrivilegedPort(port) => {
format!("Privileged port {} (requires root or capabilities)", port)
}
Self::RawSockets => "Raw IP socket access (requires root or CAP_NET_RAW)".to_string(),
Self::PacketCapture => {
"Layer-2 packet capture (requires root, CAP_NET_RAW, or BPF device access)"
.to_string()
}
Self::DeviceAccess(class) => {
format!("Access to a {} on this host", class.as_str())
}
Self::Root => "Root/Administrator access required".to_string(),
}
}
pub fn severity(&self) -> PrivilegeSeverity {
match self {
Self::None => PrivilegeSeverity::None,
Self::PrivilegedPort(_)
| Self::RawSockets
| Self::PacketCapture
| Self::DeviceAccess(_) => PrivilegeSeverity::Elevated,
Self::Root => PrivilegeSeverity::Root,
}
}
pub fn is_met_by(&self, caps: &crate::privilege::SystemCapabilities) -> bool {
match self {
Self::None => true,
Self::PrivilegedPort(_) => caps.can_bind_privileged_ports,
Self::RawSockets => caps.has_raw_socket_access,
Self::PacketCapture => caps.has_packet_capture_access,
Self::DeviceAccess(class) => caps.has_device_access(*class),
Self::Root => caps.is_root,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum DevelopmentState {
Incomplete,
Experimental,
Beta,
Stable,
}
impl DevelopmentState {
pub fn as_str(&self) -> &'static str {
match self {
Self::Incomplete => "Incomplete",
Self::Experimental => "Experimental",
Self::Beta => "Beta",
Self::Stable => "Stable",
}
}
pub const ALL: [DevelopmentState; 4] = [
Self::Incomplete,
Self::Experimental,
Self::Beta,
Self::Stable,
];
pub fn parse_ci(s: &str) -> Option<Self> {
match s.trim().to_ascii_lowercase().as_str() {
"incomplete" => Some(Self::Incomplete),
"experimental" => Some(Self::Experimental),
"beta" => Some(Self::Beta),
"stable" => Some(Self::Stable),
_ => None,
}
}
}
impl std::str::FromStr for DevelopmentState {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse_ci(s).ok_or_else(|| {
format!(
"invalid development state '{}' (expected one of: incomplete, experimental, beta, stable)",
s
)
})
}
}
#[derive(Debug, Clone)]
pub struct ProtocolMetadata {
pub state: DevelopmentState,
pub notes: Option<&'static str>,
pub privilege_requirement: PrivilegeRequirement,
}
impl ProtocolMetadata {
pub const fn new(state: DevelopmentState) -> Self {
Self {
state,
notes: None,
privilege_requirement: PrivilegeRequirement::None,
}
}
pub const fn with_notes(state: DevelopmentState, notes: &'static str) -> Self {
Self {
state,
notes: Some(notes),
privilege_requirement: PrivilegeRequirement::None,
}
}
pub const fn with_privilege(
state: DevelopmentState,
privilege_requirement: PrivilegeRequirement,
) -> Self {
Self {
state,
notes: None,
privilege_requirement,
}
}
pub const fn with_notes_and_privilege(
state: DevelopmentState,
notes: &'static str,
privilege_requirement: PrivilegeRequirement,
) -> Self {
Self {
state,
notes: Some(notes),
privilege_requirement,
}
}
pub fn is_available_to_llm(&self) -> bool {
self.state != DevelopmentState::Incomplete
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FailureMode {
Answers,
DeliberatelySilent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PortTransport {
Tcp,
Udp,
Sctp,
}
impl PortTransport {
pub fn as_str(&self) -> &'static str {
match self {
Self::Tcp => "tcp",
Self::Udp => "udp",
Self::Sctp => "sctp",
}
}
}
#[derive(Debug, Clone)]
pub struct ProtocolMetadataV2 {
pub state: DevelopmentState,
pub privilege_requirement: PrivilegeRequirement,
pub implementation: &'static str,
pub llm_control: &'static str,
pub e2e_testing: &'static str,
pub notes: Option<&'static str>,
pub connectionless: bool,
pub failure_mode: FailureMode,
pub max_inbound_bytes: Option<usize>,
pub well_known_port: Option<u16>,
pub well_known_transport: PortTransport,
pub request_only: Option<&'static str>,
}
impl ProtocolMetadataV2 {
pub const fn builder() -> ProtocolMetadataV2Builder {
ProtocolMetadataV2Builder::new()
}
pub fn is_available_to_llm(&self) -> bool {
self.state != DevelopmentState::Incomplete
}
pub fn summary(&self) -> String {
format!(
"{} - {} - LLM: {}",
self.state.as_str(),
self.implementation,
self.llm_control
)
}
}
pub struct ProtocolMetadataV2Builder {
state: DevelopmentState,
privilege_requirement: PrivilegeRequirement,
implementation: &'static str,
llm_control: &'static str,
e2e_testing: &'static str,
notes: Option<&'static str>,
connectionless: bool,
failure_mode: FailureMode,
max_inbound_bytes: Option<usize>,
well_known_port: Option<u16>,
well_known_transport: PortTransport,
request_only: Option<&'static str>,
}
impl Default for ProtocolMetadataV2Builder {
fn default() -> Self {
Self::new()
}
}
impl ProtocolMetadataV2Builder {
pub const fn new() -> Self {
Self {
state: DevelopmentState::Experimental,
privilege_requirement: PrivilegeRequirement::None,
implementation: "",
llm_control: "",
e2e_testing: "",
notes: None,
connectionless: false,
failure_mode: FailureMode::Answers,
max_inbound_bytes: None,
well_known_port: None,
well_known_transport: PortTransport::Tcp,
request_only: None,
}
}
pub const fn state(mut self, state: DevelopmentState) -> Self {
self.state = state;
self
}
pub const fn privilege_requirement(mut self, req: PrivilegeRequirement) -> Self {
self.privilege_requirement = req;
self
}
pub const fn implementation(mut self, desc: &'static str) -> Self {
self.implementation = desc;
self
}
pub const fn llm_control(mut self, desc: &'static str) -> Self {
self.llm_control = desc;
self
}
pub const fn e2e_testing(mut self, desc: &'static str) -> Self {
self.e2e_testing = desc;
self
}
pub const fn notes(mut self, notes: &'static str) -> Self {
self.notes = Some(notes);
self
}
pub const fn deliberately_silent(mut self) -> Self {
self.failure_mode = FailureMode::DeliberatelySilent;
self
}
pub const fn answers_on_failure(mut self) -> Self {
self.failure_mode = FailureMode::Answers;
self
}
pub const fn connectionless(mut self) -> Self {
self.connectionless = true;
self
}
pub const fn max_inbound_bytes(mut self, bytes: usize) -> Self {
self.max_inbound_bytes = Some(bytes);
self
}
pub const fn well_known_port(mut self, port: u16) -> Self {
self.well_known_port = Some(port);
self.well_known_transport = PortTransport::Tcp;
self
}
pub const fn well_known_udp_port(mut self, port: u16) -> Self {
self.well_known_port = Some(port);
self.well_known_transport = PortTransport::Udp;
self
}
pub const fn well_known_sctp_port(mut self, port: u16) -> Self {
self.well_known_port = Some(port);
self.well_known_transport = PortTransport::Sctp;
self
}
pub const fn port_transport(mut self, transport: PortTransport) -> Self {
self.well_known_transport = transport;
self
}
pub const fn request_only(mut self, reason: &'static str) -> Self {
self.request_only = Some(reason);
self
}
pub const fn build(self) -> ProtocolMetadataV2 {
ProtocolMetadataV2 {
state: self.state,
privilege_requirement: self.privilege_requirement,
implementation: self.implementation,
llm_control: self.llm_control,
e2e_testing: self.e2e_testing,
notes: self.notes,
connectionless: self.connectionless,
failure_mode: self.failure_mode,
max_inbound_bytes: self.max_inbound_bytes,
well_known_port: self.well_known_port,
well_known_transport: self.well_known_transport,
request_only: self.request_only,
}
}
}