Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/hand/examples/fenceprobe.rs

2.4 KiB, 1 run

created by r2519314175:899, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1// fenceprobe — ask the fence what it actually permits, from inside it.
2//
3// Written on 2026-08-20 to settle an argument. A daimon reported that a git repository did
4// not exist; the tree it was looking at was missing `.git`, `.gitignore`, `.claude` and
5// `target`, and the fence was the obvious suspect. It was not: this probe plans the real
6// fence over the real workspace, applies it, and lists the directory from inside, and every
7// entry was present and stat-able. The cause was elsewhere — the browser was open on a
8// second machine whose copy of the tree is made by Syncthing, and `.stignore` there holds
9// `target` and `.*`.
10//
11// It is kept because the question recurs and reasoning about Landlock is unreliable: an
12// allow-list with no deny rules and union semantics up the tree does not behave the way
13// reading it suggests. Measure instead.
14//
15// cargo run --release --example fenceprobe --manifest-path hand/Cargo.toml
16//
17// Edit the spec below to ask about a different workspace.
18// Apply the fence a chat with ~/usr/code attached gets, then list the daimond
19// directory from inside it. Whatever is missing here, the fence is why.
20use daimond_hand::fence::{Fence, Unfenced};
21use daimond_hand::wire::FenceSpec;
22
23fn names(tag: &str) {
24 let d = "/home/jason/usr/code/web/apps/oxedyne/daimond";
25 match std::fs::read_dir(d) {
26 Ok(it) => {
27 let mut v: Vec<String> = it.filter_map(|e| e.ok())
28 .map(|e| e.file_name().to_string_lossy().into_owned()).collect();
29 v.sort();
30 println!("{}: {} entries: {}", tag, v.len(), v.join(" "));
31 },
32 Err(e) => println!("{}: read_dir failed: {}", tag, e),
33 }
34 for p in [".git", ".gitignore", ".claude", "target", "src"] {
35 let full = format!("{}/{}", d, p);
36 println!(" {:12} stat={}", p, std::fs::metadata(&full).is_ok());
37 }
38}
39
40fn main() {
41 names("BEFORE");
42 let spec = FenceSpec {
43 rw: vec!["/home/jason/usr/code".to_string()],
44 ro: vec![],
45 deny: vec![],
46 net: false,
47 };
48 let f = Fence::detect();
49 let p = match f.plan(&spec, &Unfenced::Refuse) {
50 Ok(p) => p,
51 Err(e) => { println!("plan failed: {}", e); return; },
52 };
53 match p.apply() {
54 Ok(_) => println!("--- fence applied ---"),
55 Err(e) => { println!("apply failed: {}", e); return; },
56 }
57 names("AFTER");
58}