1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub struct Envelope {
8 #[serde(default, skip_serializing_if = "Vec::is_empty")]
10 pub scopes: Vec<String>,
11 #[serde(default)]
13 pub network: NetworkPolicy,
14 #[serde(default, skip_serializing_if = "Vec::is_empty")]
16 pub filesystem: Vec<FilesystemRule>,
17 #[serde(default, skip_serializing_if = "Vec::is_empty")]
19 pub subprocess: Vec<SubprocessRule>,
20 #[serde(default)]
22 pub safety: Safety,
23 #[serde(default, skip_serializing_if = "Vec::is_empty")]
25 pub sensitive_invocations: Vec<SensitivePredicate>,
26 #[serde(default)]
28 pub data_classification: DataClassification,
29}
30
31impl Default for Envelope {
32 fn default() -> Self {
33 Self {
34 scopes: Vec::new(),
35 network: NetworkPolicy::None,
36 filesystem: Vec::new(),
37 subprocess: Vec::new(),
38 safety: Safety::ReadOnly,
39 sensitive_invocations: Vec::new(),
40 data_classification: DataClassification::Public,
41 }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
47#[serde(tag = "mode", rename_all = "snake_case")]
48pub enum NetworkPolicy {
49 #[default]
51 None,
52 AllowList {
54 rules: Vec<NetworkRule>,
56 },
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61pub struct NetworkRule {
62 pub host: String,
64 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub port: Option<u16>,
67 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub scheme: Option<String>,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74pub struct FilesystemRule {
75 pub path: String,
77 pub mode: FilesystemMode,
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
83#[serde(rename_all = "snake_case")]
84pub enum FilesystemMode {
85 Read,
87 Write,
89 Delete,
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
95pub struct SubprocessRule {
96 pub argv_pattern: Vec<String>,
98 #[serde(default, skip_serializing_if = "Vec::is_empty")]
100 pub env_allow: Vec<String>,
101 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub cwd: Option<String>,
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
108#[serde(rename_all = "kebab-case")]
109pub enum Safety {
110 #[default]
112 ReadOnly,
113 Mutating,
115 Destructive,
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
121#[serde(rename_all = "snake_case")]
122pub enum DataClassification {
123 #[default]
125 Public,
126 Pii,
128 Secret,
130}
131
132#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
134pub struct SensitivePredicate {
135 pub jsonpath: String,
137 pub matcher: SensitiveMatcher,
139}
140
141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
143#[serde(tag = "type", content = "value", rename_all = "snake_case")]
144pub enum SensitiveMatcher {
145 Exists,
147 Equals(serde_json::Value),
149 Regex(String),
151 Gt(f64),
153 Lt(f64),
155}