Skip to main content

execsurface_model/
lib.rs

1//! Versioned raw observation types for ExecSurface.
2//!
3//! Raw observations are backend evidence. PIDs/TIDs and syscall-oriented
4//! details may appear here, while canonical identity is defined later.
5
6use serde::{Deserialize, Serialize};
7
8pub mod canonical;
9
10pub const RAW_OBSERVATION_SCHEMA_VERSION: u32 = 2;
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13pub struct Observation {
14    pub schema_version: u32,
15    pub backend: BackendMetadata,
16    pub complete: bool,
17    pub outcome: CommandOutcome,
18    pub events: Vec<RawEvent>,
19    pub warnings: Vec<ObserverWarning>,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct BackendMetadata {
24    pub name: String,
25    pub platform: String,
26    pub architecture: String,
27    pub capabilities: Vec<String>,
28    pub limitations: Vec<String>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
32pub struct CommandOutcome {
33    pub exit_code: Option<i32>,
34    pub signal: Option<i32>,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct RawEvent {
39    pub sequence: u64,
40    pub tid: i32,
41    #[serde(flatten)]
42    pub kind: RawEventKind,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46#[serde(tag = "event_type", rename_all = "snake_case")]
47pub enum RawEventKind {
48    ProcessSpawn {
49        child_tid: i32,
50        mechanism: SpawnMechanism,
51    },
52    ProcessExec {
53        path: String,
54    },
55    FilePathAccess {
56        operation: FileOperation,
57        path: String,
58        flags: Option<u64>,
59    },
60    FileOpenAt2 {
61        path: String,
62        flags: u64,
63        resolve: u64,
64    },
65    FileDescriptorAccess {
66        operation: FileOperation,
67        fd: i32,
68        path: String,
69    },
70    FileRename {
71        from: String,
72        to: String,
73    },
74    NetworkConnectAttempt {
75        endpoint: NetworkEndpoint,
76    },
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
80#[serde(rename_all = "snake_case")]
81pub enum SpawnMechanism {
82    Fork,
83    Vfork,
84    Clone,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
88#[serde(rename_all = "snake_case")]
89pub enum FileOperation {
90    Open,
91    Create,
92    Delete,
93    Read,
94    Write,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
98#[serde(tag = "address_family", rename_all = "snake_case")]
99pub enum NetworkEndpoint {
100    Inet { ip: String, port: u16 },
101    Inet6 { ip: String, port: u16 },
102    Unix { path: Option<String> },
103    Other { family: u16 },
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107pub struct ObserverWarning {
108    pub code: String,
109    pub tid: Option<i32>,
110    pub message: String,
111}
112
113impl Observation {
114    pub fn empty(backend: BackendMetadata) -> Self {
115        Self {
116            schema_version: RAW_OBSERVATION_SCHEMA_VERSION,
117            backend,
118            complete: true,
119            outcome: CommandOutcome::default(),
120            events: Vec::new(),
121            warnings: Vec::new(),
122        }
123    }
124}