summaryrefslogtreecommitdiff
path: root/build.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-21 14:23:27 -0300
committerGabriel Schneider <[email protected]>2026-09-21 15:20:40 -0300
commitb4db588dd5b92d647b661c2dc17b40925af92348 (patch)
tree7a036e500251d7f3f958854dcf3a8ead375bbc63 /build.zig
parent0d7e295efee1fca0935cf4a8bee9629c007dd2b6 (diff)
downloadcloud9-b4db588dd5b92d647b661c2dc17b40925af92348.tar.gz
cloud9-b4db588dd5b92d647b661c2dc17b40925af92348.zip
9harness: the harness fs daemon
The last item of the 9P plan, replacing zmxify's introspection half: a read-only, fresh-from-disk 9P view of every agent harness's state on this machine, posted as `harness` like any other service, so a shell inside a 9ns --mntgen mount reads it at /mnt/9p/harness with no setup. /pid /uptime /claude/{projects,history,skills} /codex/{sessions,session-index,history} /omp /hermes /dsh the mirrors /skills/{claude,codex,omp} Nothing is cached: a lookup, getattr or readdir walks the real filesystem, so a transcript grows as its harness writes it and a new session appears as soon as its file lands. Writes answer EPERM, and no name that looks like a credential, key, token or auth store is ever answered at any depth. Three findings from the adversarial pass, each with its regression: - The read path composed <base>/<rel> and opened it in one call, which follows symlinks. A name swapped for a link between the walk and the read served bytes from outside every pinned root (proved against /etc/passwd). Every stat, read and readdir now resolves through openIn, which walks from the base one component at a time with O_NOFOLLOW, and O_PATH for the intermediates, so no component can redirect the walk. O_PATH also keeps a fifo in a root from parking the daemon in open(); a read refuses anything but a regular file. - Joining a child onto an empty relative path returned an uncopied scratch slice, so every file at the top of a mirror root (/hermes/x, /dsh/x) listed but read back uninitialized stack bytes. - A directory past the comptime caps was served short, and a short listing cannot be told from a small directory. The caps answer NFILE now. Staging also stops at the first record that does not fit instead of packing a shorter one behind it, which dropped that entry from the listing across the read boundary. Suites: 13/13 unit (fake HOME, never the live roots), 36/0 end-to-end including the mntgen money shot and the live ~/.claude/.credentials.json proved unreachable, 131/131 programs-test.
Diffstat (limited to 'build.zig')
-rw-r--r--build.zig20
1 files changed, 20 insertions, 0 deletions
diff --git a/build.zig b/build.zig
index 334da9f..795d8e2 100644
--- a/build.zig
+++ b/build.zig
@@ -156,6 +156,7 @@ pub fn build(b: *std.Build) void {
const is_linux = target.result.os.tag == .linux;
const want_9proc = b.option(bool, "9proc", "Build the 9proc library module and demo (default: target is Linux)") orelse is_linux;
const want_9ns = b.option(bool, "9ns", "Build the 9ns FUSE mount CLI (default: target is Linux; Linux only)") orelse is_linux;
+ const want_9harness = b.option(bool, "9harness", "Build the harness fs daemon (default: target is Linux; Linux only)") orelse is_linux;
if (want_9ns and !is_linux) {
std.debug.print("error: -D9ns=true needs a Linux target (got {s})\n", .{@tagName(target.result.os.tag)});
std.process.exit(1);
@@ -206,6 +207,25 @@ pub fn build(b: *std.Build) void {
programs_itest.dependOn(p.itest_step);
}
+ // The harness fs daemon: a read-only 9P view of every harness's
+ // state, posted by default as `harness` (Linux only: it posts into
+ // $XDG_RUNTIME_DIR/9p through cloud9.post).
+ if (want_9harness and !is_linux) {
+ std.debug.print("error: -D9harness=true needs a Linux target (got {s})\n", .{@tagName(target.result.os.tag)});
+ std.process.exit(1);
+ }
+ const harness_build = @import("9harness/build.zig");
+ const harness: ?harness_build.Artifacts = if (want_9harness) harness_build.add(b, .{
+ .target = target,
+ .optimize = optimize,
+ .cloud9 = module,
+ .ns = if (ns) |p| p.exe else null,
+ }) else null;
+ if (harness) |p| {
+ programs_test.dependOn(p.test_step);
+ programs_itest.dependOn(p.itest_step);
+ }
+
// 9proc's end-to-end suites drive the demo through a 9ns mount,
// so they are wired once both fragments have run.
if (proc) |i| {