use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Verification {
Verified { evidence: String },
Absent {
deviation: &'static str,
reason: String,
},
}
impl Verification {
#[must_use]
pub fn is_verified(&self) -> bool {
matches!(self, Self::Verified { .. })
}
#[must_use]
pub fn deviation(&self) -> Option<&'static str> {
match self {
Self::Absent { deviation, .. } => Some(deviation),
Self::Verified { .. } => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FailClosed {
pub deviation: &'static str,
pub reason: String,
}
impl fmt::Display for FailClosed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"refused (fail-closed): OCAP invariant '{}' is not enforced — {}",
self.deviation, self.reason
)
}
}
impl std::error::Error for FailClosed {}
fn require(v: Verification) -> Result<(), FailClosed> {
match v {
Verification::Verified { .. } => Ok(()),
Verification::Absent { deviation, reason } => Err(FailClosed { deviation, reason }),
}
}
#[must_use]
pub fn verify_b1() -> Verification {
Verification::Absent {
deviation: "b1-os-isolation",
reason: "no OS sandbox or egress proxy; the in-process monitor is the only barrier".into(),
}
}
#[must_use]
pub fn verify_disclosure_gate() -> Verification {
Verification::Absent {
deviation: "disclosure-gate-live-path",
reason: "no single disclosure chokepoint on the live tool-result path".into(),
}
}
#[derive(Debug, Clone)]
pub struct ScopedCredential {
pub label: String,
}
pub fn seed_live_credential(cred: &ScopedCredential) -> Result<(), FailClosed> {
require(verify_b1())?;
require(verify_disclosure_gate())?;
let _ = cred;
Ok(())
}
pub fn admit_untrusted_remote(voice_fingerprint: &str) -> Result<(), FailClosed> {
require(verify_b1())?;
let _ = voice_fingerprint;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verifiers_are_absent_until_built() {
assert!(!verify_b1().is_verified());
assert_eq!(verify_b1().deviation(), Some("b1-os-isolation"));
assert!(!verify_disclosure_gate().is_verified());
assert_eq!(
verify_disclosure_gate().deviation(),
Some("disclosure-gate-live-path")
);
}
#[test]
fn verified_reports_no_deviation() {
let v = Verification::Verified {
evidence: "synthetic".into(),
};
assert!(v.is_verified());
assert_eq!(v.deviation(), None);
}
#[test]
fn seed_live_credential_fails_closed_on_b1() {
let cred = ScopedCredential {
label: "pa-token".into(),
};
let err = seed_live_credential(&cred).unwrap_err();
assert_eq!(err.deviation, "b1-os-isolation");
assert!(err.to_string().contains("fail-closed"));
}
#[test]
fn admit_untrusted_remote_fails_closed() {
let err = admit_untrusted_remote("SHA256:deadbeef").unwrap_err();
assert_eq!(err.deviation, "b1-os-isolation");
}
#[test]
fn require_passes_only_when_verified() {
assert!(require(Verification::Verified {
evidence: "ok".into()
})
.is_ok());
assert!(require(verify_b1()).is_err());
}
}
use base64::Engine as _;
#[derive(Debug, Default, Clone)]
pub struct DisclosureFilter {
secrets: Vec<String>,
}
impl DisclosureFilter {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, secret: impl Into<String>) {
let s = secret.into();
if !s.is_empty() {
self.secrets.push(s);
}
}
fn encodings(secret: &str) -> [String; 3] {
let bytes = secret.as_bytes();
let b64 = base64::engine::general_purpose::STANDARD.encode(bytes);
let hex: String = bytes.iter().map(|b| format!("{b:02x}")).collect();
[secret.to_string(), b64, hex]
}
#[must_use]
pub fn leaks(&self, text: &str) -> bool {
self.secrets
.iter()
.any(|s| Self::encodings(s).iter().any(|e| text.contains(e.as_str())))
}
#[must_use]
pub fn redact(&self, text: &str) -> String {
let mut out = text.to_string();
for s in &self.secrets {
for enc in Self::encodings(s) {
out = out.replace(enc.as_str(), "[REDACTED]");
}
}
out
}
}
#[cfg(test)]
mod disclosure_tests {
use super::*;
fn b64(s: &str) -> String {
base64::engine::general_purpose::STANDARD.encode(s.as_bytes())
}
fn hexs(s: &str) -> String {
s.as_bytes().iter().map(|b| format!("{b:02x}")).collect()
}
#[test]
fn catches_raw_value() {
let mut f = DisclosureFilter::new();
f.register("CANARY-7f3a9c2b");
assert!(f.leaks("the token is CANARY-7f3a9c2b right here"));
assert!(!f.leaks("nothing secret in this text"));
}
#[test]
fn catches_base64_reencoding() {
let mut f = DisclosureFilter::new();
f.register("CANARY-7f3a9c2b");
let leaked = format!("here is {} encoded", b64("CANARY-7f3a9c2b"));
assert!(f.leaks(&leaked), "base64 re-encoding must still be caught");
}
#[test]
fn catches_hex_reencoding() {
let mut f = DisclosureFilter::new();
f.register("CANARY-7f3a9c2b");
assert!(f.leaks(&format!("payload={}", hexs("CANARY-7f3a9c2b"))));
}
#[test]
fn redacts_all_forms() {
let mut f = DisclosureFilter::new();
f.register("SECRETVAL-abc123");
let text = format!(
"raw=SECRETVAL-abc123 b64={} hex={}",
b64("SECRETVAL-abc123"),
hexs("SECRETVAL-abc123")
);
let red = f.redact(&text);
assert!(!f.leaks(&red), "redacted text must not leak");
assert!(red.contains("[REDACTED]"));
}
#[test]
fn value_filter_not_shape_filter() {
let f = DisclosureFilter::new();
assert!(!f.leaks("AKIAIOSFODNN7EXAMPLE looks like a key but isn't registered"));
}
#[test]
fn empty_registration_is_ignored() {
let mut f = DisclosureFilter::new();
f.register("");
assert!(!f.leaks("anything at all"));
}
}
#[must_use]
pub fn proposer_distinct(proposer_fp: &str, worker_fp: &str) -> bool {
!proposer_fp.is_empty() && proposer_fp != worker_fp
}
#[must_use]
pub fn verify_sod(proposer_fp: &str, worker_fp: &str) -> Verification {
if !proposer_distinct(proposer_fp, worker_fp) {
return Verification::Absent {
deviation: "sod-proposer-not-worker",
reason: "proposer key is not distinct from the worker (self-proposal)".into(),
};
}
Verification::Absent {
deviation: "sod-proposer-not-worker",
reason: "distinct proposer key confirmed, but taint-aware observe-then-propose is unbuilt"
.into(),
}
}
pub fn auto_apply_policy(proposer_fp: &str, worker_fp: &str) -> Result<(), FailClosed> {
require(verify_sod(proposer_fp, worker_fp))?;
Ok(())
}
#[cfg(test)]
mod sod_tests {
use super::*;
#[test]
fn distinctness_primitive() {
assert!(proposer_distinct("SHA256:proposer", "SHA256:worker"));
assert!(!proposer_distinct("SHA256:same", "SHA256:same"));
assert!(
!proposer_distinct("", "SHA256:worker"),
"empty proposer is not distinct"
);
}
#[test]
fn verify_sod_is_absent_until_taint_aware() {
let v = verify_sod("SHA256:proposer", "SHA256:worker");
assert!(!v.is_verified());
assert_eq!(v.deviation(), Some("sod-proposer-not-worker"));
let self_prop = verify_sod("SHA256:same", "SHA256:same");
assert!(
matches!(self_prop, Verification::Absent { reason, .. } if reason.contains("self-proposal"))
);
}
#[test]
fn auto_apply_fails_closed_both_ways() {
assert!(matches!(
auto_apply_policy("SHA256:p", "SHA256:w"),
Err(FailClosed {
deviation: "sod-proposer-not-worker",
..
})
));
assert!(auto_apply_policy("SHA256:same", "SHA256:same").is_err());
}
}