use super::target::{TargetEvidence, TargetSensitivityEvidence};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
use serde_json::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ExecutionMode {
Shadow,
Background,
Foreground,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ActionClass {
Observe,
Navigate,
EditReversible,
CommunicateExternal,
Authentication,
Financial,
Destructive,
PrivilegeChange,
SecretAccess,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ActionResourceContext {
#[serde(skip_serializing_if = "Option::is_none")]
pub target_app_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_window_id: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub filesystem_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub filesystem_destination: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub registry_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub process_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub process_id: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub browser_domain: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ActionProvenance {
pub untrusted_instruction: bool,
pub source_observation_ids: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub crosses_data_boundary: Option<bool>,
}
fn deserialize_false<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
D: Deserializer<'de>,
{
let value = bool::deserialize(deserializer)?;
if value {
return Err(de::Error::custom(
"process postcondition can only prove a non-running process",
));
}
Ok(false)
}
fn serialize_false<S>(value: &bool, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if *value {
return Err(serde::ser::Error::custom(
"process postcondition can only prove a non-running process",
));
}
serializer.serialize_bool(false)
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
pub enum ActionPostcondition {
#[serde(rename = "ui_element")]
UiElement {
#[serde(skip_serializing_if = "Option::is_none")]
role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
label: Option<String>,
exists: bool,
#[serde(rename = "valueDigest", skip_serializing_if = "Option::is_none")]
value_digest: Option<String>,
},
#[serde(rename = "filesystem")]
Filesystem {
path: String,
exists: bool,
#[serde(rename = "contentDigest", skip_serializing_if = "Option::is_none")]
content_digest: Option<String>,
},
#[serde(rename = "registry")]
Registry {
path: String,
name: String,
exists: bool,
#[serde(rename = "valueDigest", skip_serializing_if = "Option::is_none")]
value_digest: Option<String>,
},
#[serde(rename = "process")]
Process {
pid: u32,
#[serde(deserialize_with = "deserialize_false", serialize_with = "serialize_false")]
running: bool,
},
#[serde(rename = "window")]
Window {
#[serde(rename = "windowId")]
window_id: u64,
exists: bool,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ActionEnvelope {
pub action_id: String,
pub session_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_group_id: Option<String>,
pub principal_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub agent_id: Option<String>,
pub tool: String,
pub operation: String,
pub action_class: ActionClass,
pub requested_mode: ExecutionMode,
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<TargetEvidence>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_sensitivity: Option<TargetSensitivityEvidence>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resource: Option<ActionResourceContext>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provenance: Option<ActionProvenance>,
pub data_labels: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub postcondition: Option<ActionPostcondition>,
pub reversible: bool,
pub external_side_effect: bool,
pub proposed_at: String,
pub expires_at: String,
pub args_digest: String,
}