use perspt_sdk::{
BarrierEvaluator, BarrierWitness, CandidateTransition, EffectKind, EffectProposal, SdkError,
};
#[derive(Debug, Clone, PartialEq)]
struct ChannelReading {
name: &'static str,
h_after: f64,
}
#[derive(Debug, Clone)]
pub struct OperationalSafetyBarrier {
pub protected_paths: Vec<String>,
pub secret_markers: Vec<String>,
pub network_allowlist: Vec<String>,
}
impl Default for OperationalSafetyBarrier {
fn default() -> Self {
Self {
protected_paths: vec![".git/".into(), ".github/workflows/".into()],
secret_markers: vec![
".env".into(),
".pem".into(),
"id_rsa".into(),
"credentials".into(),
".aws/".into(),
".ssh/".into(),
],
network_allowlist: Vec::new(),
}
}
}
impl OperationalSafetyBarrier {
pub fn measure_channels<'a>(
&self,
mutated_paths: impl IntoIterator<Item = &'a str>,
) -> std::collections::BTreeMap<String, f64> {
let mut protected = false;
let mut secret = false;
let mut escape = false;
for path in mutated_paths {
let touches = |marker: &str| path.contains(marker.trim_end_matches('/'));
protected |= self.protected_paths.iter().any(|p| touches(p));
secret |= self.secret_markers.iter().any(|m| touches(m));
escape |= path.starts_with('/') || path.split('/').any(|c| c == "..");
}
let boolean = |unsafe_now: bool| if unsafe_now { 1.0 } else { 0.0 };
std::collections::BTreeMap::from([
(
"protected-path-modification".to_string(),
boolean(protected),
),
("secret-exposure".to_string(), boolean(secret)),
("sandbox-escape".to_string(), boolean(escape)),
])
}
fn readings(&self, proposal: &EffectProposal) -> Vec<ChannelReading> {
let path = proposal.path.as_deref().unwrap_or("");
let mutating = !proposal.effect.is_read_only();
let touches =
|marker: &str| !path.is_empty() && path.contains(marker.trim_end_matches('/'));
let protected = mutating && self.protected_paths.iter().any(|p| touches(p));
let escape = mutating && (path.starts_with('/') || path.split('/').any(|c| c == ".."));
let secret = mutating && self.secret_markers.iter().any(|m| touches(m));
let network = match proposal.network_target.as_deref() {
None => false,
Some(target) => !self
.network_allowlist
.iter()
.any(|allowed| target.contains(allowed.as_str())),
};
let dependency =
proposal.effect == EffectKind::MutateDependencies && proposal.command.is_none();
let boolean = |unsafe_now: bool| if unsafe_now { 1.0 } else { 0.0 };
vec![
ChannelReading {
name: "protected-path-modification",
h_after: boolean(protected),
},
ChannelReading {
name: "sandbox-escape",
h_after: boolean(escape),
},
ChannelReading {
name: "secret-exposure",
h_after: boolean(secret),
},
ChannelReading {
name: "unapproved-network-reachability",
h_after: boolean(network),
},
ChannelReading {
name: "dependency-policy-violation",
h_after: boolean(dependency),
},
ChannelReading {
name: "resource-limits",
h_after: 0.0,
},
]
}
}
impl BarrierEvaluator for OperationalSafetyBarrier {
fn evaluate(&self, transition: &CandidateTransition) -> Result<BarrierWitness, SdkError> {
let proposal = &transition.proposal;
let readings = self.readings(proposal);
let h_before = transition
.before
.barrier_channels
.values()
.copied()
.fold(0.0, f64::max);
let measured_after = transition
.after
.barrier_channels
.values()
.copied()
.fold(0.0, f64::max);
let h_after = readings
.iter()
.map(|r| r.h_after)
.fold(measured_after, f64::max);
let c_t = (h_after - h_before).max(0.0);
Ok(BarrierWitness {
h_before,
expected_h_after_upper: h_after,
certified_increment: c_t,
unsafe_threshold: 1.0,
evidence_refs: readings
.iter()
.map(|r| format!("channel:{}@1={}", r.name, r.h_after))
.chain([
format!("state-before:{}", transition.before.state_root),
format!("state-after:{}", transition.after.state_root),
])
.collect(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use perspt_sdk::{ActorId, EffectProposal};
fn proposal(effect: EffectKind, path: Option<&str>) -> EffectProposal {
let mut p = EffectProposal::new(ActorId::new("worker"), "n1", effect);
if let Some(path) = path {
p = p.with_path(path);
}
p
}
fn transition(effect: EffectKind, path: Option<&str>) -> CandidateTransition {
CandidateTransition::unmeasured(proposal(effect, path))
}
#[test]
fn a_workspace_edit_has_zero_increment_by_measurement() {
let barrier = OperationalSafetyBarrier::default();
let witness = barrier
.evaluate(&transition(EffectKind::ApplyPatch, Some("src/lib.rs")))
.unwrap();
assert_eq!(witness.certified_increment, 0.0);
assert!(witness.clause_holds(0.0));
}
#[test]
fn protected_path_modification_crosses_the_boundary() {
let barrier = OperationalSafetyBarrier::default();
let witness = barrier
.evaluate(&transition(EffectKind::ApplyPatch, Some(".git/config")))
.unwrap();
assert!(!witness.clause_holds(1.0));
}
#[test]
fn reading_a_protected_path_is_not_a_barrier_event() {
let barrier = OperationalSafetyBarrier::default();
let witness = barrier
.evaluate(&transition(EffectKind::ReadFile, Some(".git/config")))
.unwrap();
assert_eq!(witness.certified_increment, 0.0);
}
#[test]
fn parent_traversal_is_a_sandbox_escape() {
let barrier = OperationalSafetyBarrier::default();
let witness = barrier
.evaluate(&transition(
EffectKind::WriteArtifact,
Some("../outside.rs"),
))
.unwrap();
assert!(!witness.clause_holds(1.0));
}
#[test]
fn secret_material_is_a_channel_violation() {
let barrier = OperationalSafetyBarrier::default();
let witness = barrier
.evaluate(&transition(EffectKind::WriteArtifact, Some(".env")))
.unwrap();
assert!(!witness.clause_holds(1.0));
}
#[test]
fn unallowlisted_network_target_violates() {
let barrier = OperationalSafetyBarrier::default();
let mut p = proposal(EffectKind::NetworkFetch, None);
p = p.with_network_target("https://example.com/payload");
let witness = barrier
.evaluate(&CandidateTransition::unmeasured(p))
.unwrap();
assert!(!witness.clause_holds(1.0));
}
}