use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
pub struct AgentConfig {
pub tenant_id: String,
pub agent_id: String,
pub data_plane_url: String,
pub control_plane_url: String,
pub approval_timeout_ms: u64,
pub approval_poll_ms: u64,
pub api_key: Option<String>,
}
impl AgentConfig {
pub fn new(tenant_id: impl Into<String>, agent_id: impl Into<String>) -> Self {
Self {
tenant_id: tenant_id.into(),
agent_id: agent_id.into(),
data_plane_url: "http://localhost:9090".to_string(),
control_plane_url: "http://localhost:8080/api".to_string(),
approval_timeout_ms: 30_000,
approval_poll_ms: 2_000,
api_key: None,
}
}
pub fn with_api_key(mut self, api_key: impl Into<String>) -> Self {
self.api_key = Some(api_key.into());
self
}
pub fn with_data_plane_url(mut self, url: impl Into<String>) -> Self {
self.data_plane_url = url.into();
self
}
pub fn with_control_plane_url(mut self, url: impl Into<String>) -> Self {
self.control_plane_url = url.into();
self
}
pub fn with_approval_timeout_ms(mut self, ms: u64) -> Self {
self.approval_timeout_ms = ms;
self
}
pub fn with_approval_poll_ms(mut self, ms: u64) -> Self {
self.approval_poll_ms = ms;
self
}
pub fn from_env() -> Result<Self, crate::SdkError> {
let tenant_id = std::env::var("COTS_TENANT_ID")
.map_err(|_| crate::SdkError::Config("COTS_TENANT_ID is not set".into()))?;
let agent_id = std::env::var("COTS_AGENT_ID")
.map_err(|_| crate::SdkError::Config("COTS_AGENT_ID is not set".into()))?;
let mut cfg = Self::new(tenant_id, agent_id);
if let Ok(v) = std::env::var("COTS_DATA_PLANE_URL") {
cfg.data_plane_url = v;
}
if let Ok(v) = std::env::var("COTS_CONTROL_PLANE_URL") {
cfg.control_plane_url = v;
}
if let Ok(v) = std::env::var("COTS_APPROVAL_TIMEOUT_MS") {
cfg.approval_timeout_ms = v.parse().unwrap_or(cfg.approval_timeout_ms);
}
if let Ok(v) = std::env::var("COTS_APPROVAL_POLL_MS") {
cfg.approval_poll_ms = v.parse().unwrap_or(cfg.approval_poll_ms);
}
if let Ok(v) = std::env::var("COTS_API_KEY") {
cfg.api_key = Some(v);
}
Ok(cfg)
}
}
#[derive(Debug, Clone, Default)]
pub struct NormalizedAction {
pub target_system: String,
pub action_type: String,
pub action_name: Option<String>,
pub principal_id: Option<String>,
pub session_id: Option<String>,
pub data_classification: Option<String>,
pub risk_score: Option<i32>,
pub amount: Option<f64>,
pub recipient: Option<String>,
}
impl NormalizedAction {
pub fn new(target_system: impl Into<String>, action_type: impl Into<String>) -> Self {
Self {
target_system: target_system.into(),
action_type: action_type.into(),
..Default::default()
}
}
}
#[derive(Debug, Serialize)]
pub(crate) struct InterceptWireBody {
pub tenant_id: String,
pub agent_id: String,
pub target_system: String,
pub action_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub action_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub principal_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data_classification: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub risk_score: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub amount: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub recipient: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct InterceptResult {
pub action_event_id: String,
pub tenant_id: String,
pub decision: String, pub status: String,
pub matched_rules: Vec<String>,
pub latency_ms: u128,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ApprovalOutcome {
Approved,
Denied,
Timeout,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GovernedOutcome {
Executed,
Blocked,
Timeout,
}
#[derive(Debug, Clone)]
pub struct GovernedResult<T> {
pub action_event_id: String,
pub decision: String,
pub outcome: GovernedOutcome,
pub matched_rules: Vec<String>,
pub detail: Option<T>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Tenant {
pub tenant_id: String,
pub name: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct OrgUser {
pub user_id: String,
pub email: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct TenantRegistration {
pub tenant: Tenant,
pub admin_user: OrgUser,
pub approver_user: OrgUser,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Agent {
pub agent_id: String,
pub tenant_id: String,
pub status: String,
pub api_key: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct LoginResult {
pub user: LoggedInUser,
pub role_ids: Vec<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct LoggedInUser {
pub user_id: String,
pub tenant_id: String,
pub email: String,
pub name: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct PepConfig {
pub agent_id: String,
pub tenant_id: String,
pub environment: String,
pub policy_set_id: String,
pub pep_endpoint: String,
pub approval_mode: String,
pub audit_mode: String,
pub connector_id: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ActionEventStatus {
pub action_event_id: String,
pub status: String,
pub policy_decision: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ApprovalRequest {
pub approval_request_id: String,
pub action_event_id: String,
pub status: String,
}