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