use assay_evidence::types::PayloadSandboxDegraded;
#[derive(Debug, Clone)]
pub enum ProfileEvent {
Counter { name: String, inc: u64 },
EnvProvidedKeys {
key: String,
scrubbed: bool,
},
ExecObserved { argv0: String },
FsObserved {
op: FsOp,
path: String,
backend: BackendHint,
},
AuditFallback {
reason: String,
detail: Option<String>,
},
SandboxDegraded { payload: PayloadSandboxDegraded },
EnforcementFailed {
reason: String,
detail: Option<String>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum FsOp {
Read,
Write,
Exec,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum BackendHint {
Injected,
Landlock,
Ptrace,
Ebpf,
}
impl FsOp {
pub fn as_str(&self) -> &'static str {
match self {
FsOp::Read => "read",
FsOp::Write => "write",
FsOp::Exec => "exec",
}
}
}
impl BackendHint {
pub fn as_str(&self) -> &'static str {
match self {
BackendHint::Injected => "injected",
BackendHint::Landlock => "landlock",
BackendHint::Ptrace => "ptrace",
BackendHint::Ebpf => "ebpf",
}
}
}
#[cfg(any(test, feature = "profile-test-hook"))]
pub fn try_load_test_events() -> Option<Vec<ProfileEvent>> {
use std::env;
let raw = env::var("ASSAY_PROFILE_TEST_EVENTS").ok()?;
let v: serde_json::Value = serde_json::from_str(&raw).ok()?;
let arr = v.as_array()?;
let mut out = Vec::new();
for item in arr {
let obj = item.as_object()?;
if let Some(c) = obj.get("Counter") {
let c = c.as_object()?;
out.push(ProfileEvent::Counter {
name: c.get("name")?.as_str()?.to_string(),
inc: c.get("inc")?.as_u64()?,
});
} else if let Some(e) = obj.get("EnvProvidedKeys") {
let e = e.as_object()?;
out.push(ProfileEvent::EnvProvidedKeys {
key: e.get("key")?.as_str()?.to_string(),
scrubbed: e.get("scrubbed")?.as_bool().unwrap_or(false),
});
} else if let Some(e) = obj.get("ExecObserved") {
let e = e.as_object()?;
out.push(ProfileEvent::ExecObserved {
argv0: e.get("argv0")?.as_str()?.to_string(),
});
} else if let Some(f) = obj.get("FsObserved") {
let f = f.as_object()?;
let op_str = f.get("op")?.as_str()?;
let op = match op_str {
"Read" => FsOp::Read,
"Write" => FsOp::Write,
"Exec" => FsOp::Exec,
_ => continue,
};
out.push(ProfileEvent::FsObserved {
op,
path: f.get("path")?.as_str()?.to_string(),
backend: BackendHint::Injected,
});
} else if let Some(d) = obj.get("AuditFallback") {
let d = d.as_object()?;
out.push(ProfileEvent::AuditFallback {
reason: d.get("reason")?.as_str()?.to_string(),
detail: d.get("detail").and_then(|v| v.as_str()).map(String::from),
});
} else if let Some(d) = obj.get("SandboxDegraded") {
out.push(ProfileEvent::SandboxDegraded {
payload: serde_json::from_value(d.clone()).ok()?,
});
} else if let Some(d) = obj.get("EnforcementFailed") {
let d = d.as_object()?;
out.push(ProfileEvent::EnforcementFailed {
reason: d.get("reason")?.as_str()?.to_string(),
detail: d.get("detail").and_then(|v| v.as_str()).map(String::from),
});
}
}
Some(out)
}