use std::path::{Path, PathBuf};
use chrono::{DateTime, Utc};
use crate::core::hook_state::{hash_settings_path, HookStateFile};
use crate::hooks::cline::SurfaceState;
use crate::hooks::cursor::IdeLocation;
use crate::hooks::entry_shape;
pub const AGENT: &str = "cursor";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SurfaceReport {
pub state: SurfaceState,
pub version: Option<String>,
pub unreadable: Option<String>,
}
impl SurfaceReport {
fn present(version: Option<String>) -> Self {
Self {
state: SurfaceState::Present,
version,
unreadable: None,
}
}
fn absent() -> Self {
Self {
state: SurfaceState::Absent,
version: None,
unreadable: None,
}
}
fn undetermined(what: String) -> Self {
Self {
state: SurfaceState::Undetermined,
version: None,
unreadable: Some(what),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HookFileState {
Present,
Absent,
Malformed,
}
impl HookFileState {
pub fn as_str(self) -> &'static str {
match self {
Self::Present => "present",
Self::Absent => "absent",
Self::Malformed => "malformed",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Reachability {
Proven,
Pending,
Failed,
}
impl Reachability {
pub fn as_str(self) -> &'static str {
match self {
Self::Proven => "proven",
Self::Pending => "pending",
Self::Failed => "failed",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelayDelivery {
Wired,
Unwired,
Unsupported,
}
impl RelayDelivery {
pub fn as_str(self) -> &'static str {
match self {
Self::Wired => "wired",
Self::Unwired => "unwired",
Self::Unsupported => "unsupported",
}
}
}
pub const UNPROVEN_REMEDY: &str =
"Start one Cursor agent turn (CLI: run `cursor-agent` from a new \
terminal). This turns green on the first decrypted request.";
pub const UNSUPPORTED_REMEDY: &str = "Nothing to do: this build does not route that Cursor surface \
through the relay, so its model calls go direct and are not measured; its hooks still enforce.";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CursorRelay {
pub cli: RelayDelivery,
pub ide: RelayDelivery,
pub traffic_proven: bool,
pub unwired: Option<(&'static str, String)>,
}
impl CursorRelay {
pub fn findings(&self) -> Vec<(&'static str, &'static str, &'static str, String)> {
let mut out = Vec::new();
for (field, delivery) in [("cli", self.cli), ("ide", self.ide)] {
match delivery {
RelayDelivery::Wired => {}
RelayDelivery::Unsupported => out.push((
field,
delivery.as_str(),
crate::error::ERR_CURSOR_RELAY_UNSUPPORTED,
UNSUPPORTED_REMEDY.to_string(),
)),
RelayDelivery::Unwired => {
let (code, remedy) = self.unwired.clone().unwrap_or((
crate::error::ERR_MODEL_RELAY_PREFLIGHT_FAILED,
"Run `openlatch doctor --fix`; the relay wires Cursor once its preflight \
passes."
.to_string(),
));
out.push((field, delivery.as_str(), code, remedy));
}
}
}
if !self.traffic_proven {
out.push((
"traffic",
self.traffic_str(),
crate::error::ERR_CURSOR_RELAY_UNPROVEN,
UNPROVEN_REMEDY.to_string(),
));
}
out
}
fn traffic_str(&self) -> &'static str {
if self.traffic_proven {
"proven"
} else {
"unproven"
}
}
fn to_json(&self) -> serde_json::Value {
let findings: Vec<serde_json::Value> = self
.findings()
.into_iter()
.map(|(field, state, code, remedy)| {
serde_json::json!({
"field": field,
"state": state,
"code": code,
"remedy": remedy,
})
})
.collect();
serde_json::json!({
"cli": self.cli.as_str(),
"ide": self.ide.as_str(),
"traffic": self.traffic_str(),
"findings": findings,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CursorAttestation {
pub as_of: String,
pub store_root: Option<PathBuf>,
pub operator_supplied: bool,
pub ide: SurfaceReport,
pub cli: SurfaceReport,
pub hooks_file: HookFileState,
pub ours: bool,
pub other_hook_sources: Vec<PathBuf>,
pub claude_import: bool,
pub reachability: Reachability,
pub relay: Option<CursorRelay>,
}
pub(crate) struct Inputs {
pub openlatch_dir: PathBuf,
pub store_root: Option<PathBuf>,
pub operator_supplied: bool,
pub ide_locations: Vec<IdeLocation>,
pub ide_on_path: bool,
pub cli_dirs: Vec<PathBuf>,
pub cli_on_path: bool,
pub enterprise_files: Vec<PathBuf>,
pub claude_settings: Option<PathBuf>,
pub now: DateTime<Utc>,
}
impl Inputs {
fn from_host(openlatch_dir: &Path) -> Self {
let home = dirs::home_dir().unwrap_or_default();
let path_var = std::env::var_os("PATH");
Self {
openlatch_dir: openlatch_dir.to_path_buf(),
store_root: crate::hooks::cursor::root(),
operator_supplied: std::env::var_os(crate::hooks::cursor::CONFIG_DIR_ENV)
.is_some_and(|v| !v.is_empty()),
ide_locations: crate::hooks::cursor::ide_locations(&home),
ide_on_path: crate::hooks::cursor::ide_on_path(path_var.as_deref()),
cli_dirs: crate::hooks::cursor::cli_install_dirs(&home),
cli_on_path: crate::hooks::cursor::cli_on_path(path_var.as_deref()),
enterprise_files: crate::hooks::cursor::enterprise_dir()
.map(|dir| crate::hooks::cursor::hooks_json_path(&dir))
.into_iter()
.collect(),
claude_settings: crate::hooks::claude_code::config_dir()
.map(|dir| crate::hooks::claude_code::settings_json_path(&dir)),
now: Utc::now(),
}
}
}
pub fn probe(openlatch_dir: &Path) -> CursorAttestation {
probe_with(&Inputs::from_host(openlatch_dir))
}
pub(crate) fn probe_with(inputs: &Inputs) -> CursorAttestation {
let hooks_path = inputs
.store_root
.as_deref()
.map(crate::hooks::cursor::hooks_json_path);
let (hooks_file, ours) = match &hooks_path {
Some(path) => hook_file(&inputs.openlatch_dir, path),
None => (HookFileState::Absent, false),
};
let installed_at = hooks_path
.as_deref()
.and_then(|path| {
crate::hooks::agent_backup::installed_at(&inputs.openlatch_dir, AGENT, path)
})
.map(DateTime::<Utc>::from);
CursorAttestation {
as_of: inputs
.now
.to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
store_root: inputs.store_root.clone(),
operator_supplied: inputs.operator_supplied,
ide: probe_ide(&inputs.ide_locations, inputs.ide_on_path),
cli: probe_cli(&inputs.cli_dirs, inputs.cli_on_path),
hooks_file,
ours,
other_hook_sources: inputs
.enterprise_files
.iter()
.filter(|path| path.exists())
.cloned()
.collect(),
claude_import: inputs
.claude_settings
.as_deref()
.is_some_and(holds_openlatch_entry),
reachability: reachability(&inputs.openlatch_dir, installed_at),
relay: None,
}
}
fn probe_ide(locations: &[IdeLocation], on_path: bool) -> SurfaceReport {
let mut installed = on_path;
let mut unconfirmed: Option<String> = None;
for location in locations.iter().filter(|l| l.path.exists()) {
installed = true;
let Some(package_json) = &location.package_json else {
continue;
};
match confirm_package(package_json) {
Ok(version) => return SurfaceReport::present(version),
Err(what) => {
unconfirmed.get_or_insert(what);
}
}
}
match unconfirmed {
Some(what) => SurfaceReport::undetermined(what),
None if installed => SurfaceReport::present(None),
None => SurfaceReport::absent(),
}
}
fn confirm_package(package_json: &Path) -> Result<Option<String>, String> {
let shown = crate::core::path_compat::display_path(package_json);
let raw = std::fs::read_to_string(package_json).map_err(|e| format!("{shown}: {e}"))?;
let value: serde_json::Value =
serde_json::from_str(&raw).map_err(|e| format!("{shown} is not valid JSON: {e}"))?;
let names_cursor = value
.get("name")
.and_then(serde_json::Value::as_str)
.is_some_and(|name| name.to_ascii_lowercase().contains("cursor"));
if !names_cursor {
return Err(format!("{shown} names no Cursor product"));
}
Ok(value
.get("version")
.and_then(serde_json::Value::as_str)
.map(str::to_string))
}
fn probe_cli(install_dirs: &[PathBuf], on_path: bool) -> SurfaceReport {
let mut installed = on_path;
for dir in install_dirs.iter().filter(|d| d.exists()) {
installed = true;
let versions = dir.join("versions");
match std::fs::read_dir(&versions) {
Ok(entries) => {
let newest = entries
.filter_map(Result::ok)
.filter(|e| e.file_type().is_ok_and(|t| t.is_dir()))
.filter_map(|e| e.file_name().into_string().ok())
.max();
if newest.is_some() {
return SurfaceReport::present(newest);
}
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
Err(e) => {
return SurfaceReport::undetermined(format!(
"{}: {e}",
crate::core::path_compat::display_path(&versions)
))
}
}
}
if installed {
SurfaceReport::present(None)
} else {
SurfaceReport::absent()
}
}
fn hook_file(openlatch_dir: &Path, hooks_path: &Path) -> (HookFileState, bool) {
if !hooks_path.exists() {
return (HookFileState::Absent, false);
}
let binding = crate::hooks::bindings::cursor::CursorBinding {
root: hooks_path
.parent()
.map(Path::to_path_buf)
.unwrap_or_default(),
hooks_path: hooks_path.to_path_buf(),
};
if crate::hooks::health::root_contract_violation(hooks_path, &binding).is_some() {
return (HookFileState::Malformed, false);
}
let parsed = std::fs::read_to_string(hooks_path)
.ok()
.and_then(|raw| crate::hooks::jsonc::parse_settings_value(&raw).ok());
let ours = parsed.is_some_and(|parsed| entries_verify(openlatch_dir, hooks_path, &parsed));
(HookFileState::Present, ours)
}
fn entries_verify(openlatch_dir: &Path, hooks_path: &Path, parsed: &serde_json::Value) -> bool {
let Ok(Some(state)) = HookStateFile::load(openlatch_dir) else {
return false;
};
let Some(key) =
crate::core::hook_state::key::HmacKeyStore::new(openlatch_dir).load_existing_file()
else {
return false;
};
let hash = hash_settings_path(hooks_path);
let mut rows = state
.entries
.iter()
.filter(|row| row.agent == AGENT && row.settings_path_hash == hash)
.peekable();
rows.peek().is_some()
&& rows.all(|row| {
parsed["hooks"][&row.hook_event]
.as_array()
.is_some_and(|entries| {
entries.iter().any(|entry| {
entry_shape::is_sidecar_owned_entry(entry, AGENT)
&& crate::core::hook_state::hmac::verify_entry_hmac(
entry,
&row.expected_entry_hmac,
&key,
)
.unwrap_or(false)
})
})
})
}
pub(crate) fn holds_openlatch_entry(path: &Path) -> bool {
let Some(parsed) = std::fs::read_to_string(path)
.ok()
.and_then(|raw| crate::hooks::jsonc::parse_settings_value(&raw).ok())
else {
return false;
};
parsed
.get("hooks")
.and_then(serde_json::Value::as_object)
.is_some_and(|events| {
events
.values()
.filter_map(serde_json::Value::as_array)
.flatten()
.flat_map(entry_shape::entry_commands)
.any(entry_shape::is_openlatch_command)
})
}
fn reachability(openlatch_dir: &Path, installed_at: Option<DateTime<Utc>>) -> Reachability {
let since = |at: &DateTime<Utc>| installed_at.is_none_or(|installed| *at >= installed);
if crate::daemon::agent_liveness::read(openlatch_dir)
.get(AGENT)
.is_some_and(since)
{
return Reachability::Proven;
}
if fallback_holds_event(
&openlatch_dir.join("logs").join("fallback.jsonl"),
&since,
installed_at.is_none(),
) {
return Reachability::Failed;
}
Reachability::Pending
}
fn fallback_holds_event(
path: &Path,
since: &dyn Fn(&DateTime<Utc>) -> bool,
undated_counts: bool,
) -> bool {
use std::io::BufRead;
let Ok(file) = std::fs::File::open(path) else {
return false;
};
std::io::BufReader::new(file)
.lines()
.map_while(Result::ok)
.filter(|line| line.contains(AGENT))
.filter_map(|line| serde_json::from_str::<serde_json::Value>(&line).ok())
.filter(|event| event["source"].as_str() == Some(AGENT))
.any(|event| {
match event["time"]
.as_str()
.and_then(|t| DateTime::parse_from_rfc3339(t).ok())
{
Some(at) => since(&at.with_timezone(&Utc)),
None => undated_counts,
}
})
}
impl CursorAttestation {
fn surfaces_not_present(&self) -> Vec<(&'static str, &SurfaceReport)> {
[("ide", &self.ide), ("cli", &self.cli)]
.into_iter()
.filter(|(_, s)| s.state != SurfaceState::Present)
.collect()
}
pub fn undetermined(&self) -> Option<(&'static str, &SurfaceReport)> {
self.surfaces_not_present()
.into_iter()
.find(|(_, s)| s.state == SurfaceState::Undetermined)
}
pub(crate) fn remedy_for(&self, surface: &'static str, report: &SurfaceReport) -> String {
let name = display_name(surface);
match report.state {
SurfaceState::Present => String::new(),
SurfaceState::Undetermined => format!(
"OpenLatch could not confirm the Cursor {name} ({}). Check its permissions, or \
reinstall Cursor, then run `openlatch doctor` again.",
report.unreadable.as_deref().unwrap_or("unreadable")
),
SurfaceState::Absent => {
let other = if surface == "ide" {
&self.cli
} else {
&self.ide
};
if other.state == SurfaceState::Present {
format!(
"Nothing to do: the Cursor {name} is not installed here. If you use it, \
install it and run `openlatch doctor` again."
)
} else {
format!("Install the Cursor {name}, then run `openlatch doctor` again.")
}
}
}
}
pub fn to_json(&self) -> serde_json::Value {
let surface = |s: &SurfaceReport| {
serde_json::json!({
"state": s.state.as_str(),
"version": s.version,
})
};
let mut out = serde_json::json!({
"as_of": self.as_of,
"store_root": {
"path": self.store_root.as_deref().map(crate::core::path_compat::display_path),
"located": if self.operator_supplied { "operator-supplied" } else { "default" },
},
"ide": surface(&self.ide),
"cli": surface(&self.cli),
"hooks_file": {
"state": self.hooks_file.as_str(),
"ours": self.ours,
},
"other_hook_sources": self
.other_hook_sources
.iter()
.map(|p| crate::core::path_compat::display_path(p))
.collect::<Vec<_>>(),
"claude_import": if self.claude_import { "active" } else { "inactive" },
"reachability": self.reachability.as_str(),
"surfaces_absent": self
.surfaces_not_present()
.into_iter()
.map(|(name, s)| serde_json::json!({
"surface": name,
"state": s.state.as_str(),
"code": (s.state == SurfaceState::Undetermined)
.then_some(crate::error::ERR_CURSOR_SURFACE_UNDETERMINED),
"remedy": self.remedy_for(name, s),
}))
.collect::<Vec<_>>(),
});
if let (Some(relay), Some(object)) = (&self.relay, out.as_object_mut()) {
object.insert("relay".to_string(), relay.to_json());
}
out
}
pub fn summary(&self) -> String {
let surface = |name: &str, s: &SurfaceReport| match (&s.state, &s.version) {
(SurfaceState::Present, Some(v)) => format!("{name} {v}"),
(state, _) => format!("{name} {}", state.as_str()),
};
format!(
"Cursor: {}, {} — {} ({})",
surface("IDE", &self.ide),
surface("CLI", &self.cli),
self.store_root
.as_deref()
.map(crate::core::path_compat::display_path)
.unwrap_or_else(|| "root unresolved".to_string()),
if self.operator_supplied {
"operator-supplied"
} else {
"default"
}
)
}
pub fn human_lines(&self) -> Vec<String> {
let mut lines = vec![
format!(
"Hook file: {}{}",
self.hooks_file.as_str(),
if self.ours {
", our entries verify"
} else {
", our entries do not all verify"
}
),
format!("Reachability: {}", self.reachability.as_str()),
format!(
"Claude Code import: {}",
if self.claude_import {
"active (Cursor runs Claude Code's OpenLatch hook, which steps aside)"
} else {
"inactive"
}
),
];
for path in &self.other_hook_sources {
lines.push(format!(
"Other hook source: {}",
crate::core::path_compat::display_path(path)
));
}
for (name, s) in self.surfaces_not_present() {
lines.push(format!(
"{} {}: {}",
display_name(name),
s.state.as_str(),
self.remedy_for(name, s)
));
}
lines
}
}
fn display_name(surface: &str) -> &'static str {
if surface == "ide" {
"IDE"
} else {
"CLI"
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Host {
_root: tempfile::TempDir,
ol: PathBuf,
cursor: PathBuf,
bundle: PathBuf,
cli: PathBuf,
claude: PathBuf,
enterprise: PathBuf,
}
impl Host {
fn new() -> Self {
let root = tempfile::tempdir().unwrap();
let p = |name: &str| root.path().join(name);
let host = Self {
ol: p("openlatch"),
cursor: p("cursor"),
bundle: p("Cursor.app"),
cli: p("cursor-agent"),
claude: p("claude-settings.json"),
enterprise: p("enterprise-hooks.json"),
_root: root,
};
std::fs::create_dir_all(&host.ol).unwrap();
std::fs::create_dir_all(&host.cursor).unwrap();
host
}
fn package_json(&self) -> PathBuf {
self.bundle.join("package.json")
}
fn inputs(&self) -> Inputs {
Inputs {
openlatch_dir: self.ol.clone(),
store_root: Some(self.cursor.clone()),
operator_supplied: true,
ide_locations: vec![IdeLocation {
path: self.bundle.clone(),
package_json: Some(self.package_json()),
}],
ide_on_path: false,
cli_dirs: vec![self.cli.clone()],
cli_on_path: false,
enterprise_files: vec![self.enterprise.clone()],
claude_settings: Some(self.claude.clone()),
now: "2026-09-30T12:00:00Z".parse().unwrap(),
}
}
fn probe(&self) -> CursorAttestation {
probe_with(&self.inputs())
}
fn install_ide(&self, package: &str) {
std::fs::create_dir_all(&self.bundle).unwrap();
std::fs::write(self.package_json(), package).unwrap();
}
}
#[test]
fn cursor_attestation_ide_present_reads_version_from_package_json() {
let host = Host::new();
host.install_ide(r#"{"name":"Cursor","version":"3.22.12"}"#);
let a = host.probe();
assert_eq!(a.ide, SurfaceReport::present(Some("3.22.12".into())));
assert_eq!(a.to_json()["ide"]["version"], "3.22.12");
host.install_ide(r#"{"name":"Cursor"}"#);
assert_eq!(host.probe().ide, SurfaceReport::present(None));
}
#[test]
fn cursor_attestation_ide_absent_is_informational_beside_a_present_cli() {
let host = Host::new();
std::fs::create_dir_all(host.cli.join("versions").join("2026.09.28-64d2043")).unwrap();
let a = host.probe();
assert_eq!(a.ide.state, SurfaceState::Absent);
let absent = &a.to_json()["surfaces_absent"];
assert_eq!(absent[0]["surface"], "ide");
assert_eq!(absent[0]["state"], "absent");
assert!(absent[0]["code"].is_null(), "absent is not a warning");
assert!(absent[0]["remedy"]
.as_str()
.unwrap()
.starts_with("Nothing to do"));
assert!(a.undetermined().is_none());
}
#[test]
fn cursor_attestation_ide_undetermined_when_bundle_cannot_be_confirmed() {
for package in [
None,
Some("{not json"),
Some(r#"{"name":"Code","version":"1.0"}"#),
] {
let host = Host::new();
std::fs::create_dir_all(&host.bundle).unwrap();
if let Some(body) = package {
std::fs::write(host.package_json(), body).unwrap();
}
let a = host.probe();
assert_eq!(a.ide.state, SurfaceState::Undetermined, "{package:?}");
assert!(a.ide.unreadable.is_some());
let (name, _) = a.undetermined().expect("an undetermined surface");
assert_eq!(name, "ide");
assert_eq!(
a.to_json()["surfaces_absent"][0]["code"],
crate::error::ERR_CURSOR_SURFACE_UNDETERMINED
);
}
}
#[test]
fn cursor_attestation_cli_version_is_the_newest_directory() {
let host = Host::new();
for v in [
"2026.08.01-aaaaaaa",
"2026.09.28-64d2043",
"2026.09.02-bbbbbbb",
] {
std::fs::create_dir_all(host.cli.join("versions").join(v)).unwrap();
}
std::fs::write(host.cli.join("versions").join("zzz-not-a-dir"), "").unwrap();
assert_eq!(
host.probe().cli,
SurfaceReport::present(Some("2026.09.28-64d2043".into()))
);
}
#[test]
fn cursor_attestation_cli_absent_and_on_path_without_versions() {
let host = Host::new();
assert_eq!(host.probe().cli.state, SurfaceState::Absent);
let mut inputs = host.inputs();
inputs.cli_on_path = true;
assert_eq!(probe_with(&inputs).cli, SurfaceReport::present(None));
}
#[cfg(unix)]
#[test]
fn cursor_attestation_cli_undetermined_when_versions_unreadable() {
use std::os::unix::fs::PermissionsExt;
let host = Host::new();
let versions = host.cli.join("versions");
std::fs::create_dir_all(&versions).unwrap();
std::fs::set_permissions(&versions, std::fs::Permissions::from_mode(0o000)).unwrap();
let readable_anyway = std::fs::read_dir(&versions).is_ok(); let cli = host.probe().cli;
std::fs::set_permissions(&versions, std::fs::Permissions::from_mode(0o755)).unwrap();
if !readable_anyway {
assert_eq!(cli.state, SurfaceState::Undetermined);
}
}
#[test]
fn cursor_attestation_store_root_reports_how_it_was_located() {
let host = Host::new();
let json = host.probe().to_json();
assert_eq!(json["store_root"]["located"], "operator-supplied");
assert_eq!(
json["store_root"]["path"],
crate::core::path_compat::display_path(&host.cursor)
);
let mut inputs = host.inputs();
inputs.operator_supplied = false;
assert_eq!(
probe_with(&inputs).to_json()["store_root"]["located"],
"default"
);
}
#[test]
fn cursor_attestation_hooks_file_states() {
let host = Host::new();
let hooks = host.cursor.join("hooks.json");
assert_eq!(host.probe().hooks_file, HookFileState::Absent);
std::fs::write(&hooks, r#"{"version":1,"hooks":{}}"#).unwrap();
let a = host.probe();
assert_eq!(a.hooks_file, HookFileState::Present);
assert!(!a.ours, "no state row, nothing of ours verifies");
for bad in ["{not json", r#"{"version":2,"hooks":{}}"#] {
std::fs::write(&hooks, bad).unwrap();
assert_eq!(host.probe().hooks_file, HookFileState::Malformed, "{bad}");
}
}
#[test]
fn cursor_attestation_hooks_file_ours_after_a_real_install() {
crate::hooks::with_cursor_install_env(|binding, ol| {
crate::hooks::install_hooks(binding, 7443, "a-token").expect("install");
let inputs = Inputs {
openlatch_dir: ol.to_path_buf(),
store_root: Some(binding.root.clone()),
..Host::new().inputs()
};
let a = probe_with(&inputs);
assert_eq!(a.hooks_file, HookFileState::Present);
assert!(a.ours, "every row verifies against the installed file");
assert_eq!(a.to_json()["hooks_file"]["ours"], true);
let mut v: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(&binding.hooks_path).unwrap())
.unwrap();
v["hooks"]["stop"][0]["timeout"] = serde_json::json!(99);
std::fs::write(&binding.hooks_path, v.to_string()).unwrap();
assert!(!probe_with(&inputs).ours);
});
}
#[test]
fn cursor_attestation_other_hook_sources_and_claude_import() {
let host = Host::new();
let a = host.probe();
assert!(a.other_hook_sources.is_empty());
assert_eq!(a.to_json()["claude_import"], "inactive");
std::fs::write(&host.enterprise, "{}").unwrap();
std::fs::write(
&host.claude,
r#"{"hooks":{"PreToolUse":[{"matcher":"","_openlatch":{"v":1},
"hooks":[{"type":"command","command":"\"/x/openlatch-hook\" --agent claude-code"}]}]}}"#,
)
.unwrap();
let a = host.probe();
assert_eq!(a.other_hook_sources, vec![host.enterprise.clone()]);
assert_eq!(a.to_json()["claude_import"], "active");
}
fn install_at(host: &Host, at: std::time::SystemTime) {
let dir = host.ol.join("agent-backups").join(AGENT);
std::fs::create_dir_all(&dir).unwrap();
let pre = dir.join("hooks.json.pre.absent");
std::fs::write(&pre, "").unwrap();
std::fs::File::options()
.write(true)
.open(&pre)
.unwrap()
.set_modified(at)
.unwrap();
}
fn write_liveness(host: &Host, at: &str) {
std::fs::write(
host.ol.join(crate::daemon::agent_liveness::FILE_NAME),
format!(r#"{{"{AGENT}":"{at}"}}"#),
)
.unwrap();
}
fn write_fallback(host: &Host, source: &str, at: &str) {
let logs = host.ol.join("logs");
std::fs::create_dir_all(&logs).unwrap();
std::fs::write(
logs.join("fallback.jsonl"),
format!(
"{}\n",
serde_json::json!({"id": "e", "source": source, "type": "stop", "time": at})
),
)
.unwrap();
}
fn at(s: &str) -> std::time::SystemTime {
s.parse::<DateTime<Utc>>().unwrap().into()
}
#[test]
fn cursor_attestation_reachability_pending_with_no_evidence() {
let host = Host::new();
install_at(&host, at("2026-09-30T10:00:00Z"));
write_fallback(&host, "claude-code", "2026-09-30T11:00:00Z");
assert_eq!(host.probe().reachability, Reachability::Pending);
assert_eq!(host.probe().to_json()["reachability"], "pending");
}
#[test]
fn cursor_attestation_reachability_proven_by_a_live_event_since_install() {
let host = Host::new();
install_at(&host, at("2026-09-30T10:00:00Z"));
write_liveness(&host, "2026-09-30T09:00:00Z");
assert_eq!(
host.probe().reachability,
Reachability::Pending,
"a live event from before the install proves nothing about it"
);
write_liveness(&host, "2026-09-30T11:00:00Z");
assert_eq!(host.probe().reachability, Reachability::Proven);
}
#[test]
fn cursor_attestation_reachability_failed_when_events_only_in_fallback() {
let host = Host::new();
install_at(&host, at("2026-09-30T10:00:00Z"));
write_fallback(&host, AGENT, "2026-09-30T09:00:00Z");
assert_eq!(
host.probe().reachability,
Reachability::Pending,
"a fallback event from before the install is not about our entries"
);
write_fallback(&host, AGENT, "2026-09-30T11:00:00Z");
assert_eq!(host.probe().reachability, Reachability::Failed);
assert_eq!(host.probe().to_json()["reachability"], "failed");
write_liveness(&host, "2026-09-30T11:30:00Z");
assert_eq!(host.probe().reachability, Reachability::Proven);
}
#[test]
fn cursor_attestation_as_of_is_rfc3339() {
let host = Host::new();
assert_eq!(host.probe().to_json()["as_of"], "2026-09-30T12:00:00Z");
}
#[test]
fn leftover_entries_reads_nested_and_flat() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("hooks.json");
assert!(!holds_openlatch_entry(&path));
std::fs::write(
&path,
r#"{"version":1,"hooks":{"stop":[{"command":"./mine.sh"}]}}"#,
)
.unwrap();
assert!(!holds_openlatch_entry(&path));
std::fs::write(
&path,
r#"{"version":1,"hooks":{"stop":[{"command":"\"/x/openlatch-hook\" --agent cursor --event stop"}]}}"#,
)
.unwrap();
assert!(holds_openlatch_entry(&path));
}
}