Ambient system companions over one privacy-preserving signal daemon (aggregate-only, no keystroke content): a git-driven terminal garden and IOKit hardware collectors. ambient daemon macos privacy terminal

crates/signald/tests/spool_bound.rs

58 lines · 1937 bytes

 1//! The spool cannot grow without bound while the daemon is away.
 2//!
 3//! The hook appends one record per prompt and the daemon consumes the spool
 4//! each tick. When the daemon is not running nothing consumes it, so the file
 5//! grew forever and the daemon then read the whole thing into memory on
 6//! recovery. The hook caps it at the source, which is the only place that
 7//! actually bounds growth.
 8
 9use std::path::PathBuf;
10use std::process::Command;
11
12fn hook_path() -> PathBuf {
13    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
14        .join("../../shell-hooks/signald-hooks.zsh")
15        .canonicalize()
16        .expect("hook script")
17}
18
19/// Source the real hook, drive `precmd` past a small cap, and check the file
20/// was truncated rather than left to grow.
21#[test]
22fn the_hook_truncates_a_spool_past_the_cap() {
23    let dir = std::env::temp_dir().join(format!("signald-spoolcap-{}", std::process::id()));
24    let _ = std::fs::remove_dir_all(&dir);
25    std::fs::create_dir_all(&dir).unwrap();
26    let spool = dir.join("terminal.spool");
27
28    let script = format!(
29        r#"
30        export SIGNALD_SPOOL={spool}
31        export SIGNALD_SPOOL_MAX_BYTES=200
32        source {hook}
33        for i in {{1..40}}; do _signald_precmd; done
34        wc -c < $SIGNALD_SPOOL
35        "#,
36        spool = spool.display(),
37        hook = hook_path().display(),
38    );
39    let out = Command::new("zsh")
40        .arg("-c")
41        .arg(&script)
42        .output()
43        .expect("zsh runs the hook");
44    assert!(
45        out.status.success(),
46        "hook failed: {}",
47        String::from_utf8_lossy(&out.stderr)
48    );
49
50    let size: u64 = String::from_utf8_lossy(&out.stdout)
51        .trim()
52        .parse()
53        .expect("wc prints a size");
54    assert!(size <= 200, "spool grew to {size} bytes past a 200-byte cap");
55    assert!(size > 0, "truncation must not stop the current record landing");
56
57    let _ = std::fs::remove_dir_all(&dir);
58}