code wiki / _hdl_build / nx_reader_library_gate.nx
nx_reader_library_gate.nx source
↩ module page · 109 lines · 7474 B
1import "nx_gate_grow.nx"
2import "nx_gate_gn.nx"
3import "nx_gate_read.nx"
4// nx_reader_library_gate.nx -- SOVEREIGN referee for the shared/personal LIBRARY spine (FLAT-SLUG convention:
5// a personal book's slug IS "u_<ukey>_<name>", so the owner is encoded in the slug the serve routes key off).
6// The core property: PRIVACY BY CONSTRUCTION -- user B can never name/reach user A's personal book. chdir /tmp.
7// T0 rl_slug_guard: shared slug ok for all; A's personal slug ok for A / denied for B; ukey-prefix (not whole)
8// denied. rl_may_access path form: reader/<shared> ok; reader/u_<A>_x ok for A / denied for B; "../" denied.
9// T1 rl_add_personal -> index row "u_<kA>_mymanga\t<title>", dir reader/u_<kA>_mymanga created; idempotent (0)
10// T2 list_personal(A) shows it; list_personal(B) EMPTY
11// T3 guard the REAL fixture paths (A yes / B no)
12// T4 promote: reader/u_<kA>_mymanga -> reader/mymanga + shared index gets "mymanga"; source gone
13// T5 NEG promote: missing -> 0 ; B promoting A's slug -> -1 (not owned) ; shared-exists -> -1 (never clobber)
14// GREEN iff 6/6. license_tier: ORIGINAL expect_exit: 0
15import "nx_syscalls.nx"
16import "nx_reader_library.nx"
17
18func gw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
19func g_has(hay: *u8, n: i64, needle: *u8) -> i64 {
20 var nn: i64 = 0; while needle[nn] != (0 as u8) { nn = nn + 1 }
21 if nn == 0 { return 0 }
22 var i: i64 = 0
23 while i + nn <= n { var m: i64 = 1; var j: i64 = 0; while j < nn { if (hay[i + j] as i64) != (needle[j] as i64) { m = 0; j = nn } else { j = j + 1 } } if m == 1 { return 1 } i = i + 1 }
24 return 0
25}
26func g_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
27func g_mkdir(path: *u8) -> i64 { __syscall(258, 0 - 100, path as i64, 0x1ed, 0, 0, 0); return 0 }
28func g_wr(path: *u8, s: *u8, n: i64) -> i64 { let fd: i64 = sys_openat_wr(path, 0x1a4); if fd >= 0 { sys_write(fd, s, n); sys_close(fd) } return 0 }
29func g_unlink(path: *u8) -> i64 { __syscall(263, 0 - 100, path, 0, 0, 0, 0); return 0 }
30
31func main() -> i64 {
32 gw("reader-library SOVEREIGN gate (flat-slug shared/personal isolation-by-construction)\n" as *u8)
33 if sys_chdir("/tmp" as *u8) != 0 { gw("CHDIR /tmp FAIL\n" as *u8); sys_exit(1) }
34 g_mkdir("knowledge" as *u8); g_mkdir("knowledge/staging" as *u8); g_mkdir("knowledge/staging/media" as *u8); g_mkdir("knowledge/staging/media/reader" as *u8)
35
36 let kA: *u8 = "elder_aa11bb22" as *u8
37 let kB: *u8 = "brad_cc33dd44" as *u8
38 var pass: i64 = 0
39
40 // ---- T0 the guard + path predicate ----
41 var t0: i64 = 1
42 if rl_slug_guard(kA, "sharedbook" as *u8) != 1 { t0 = 0 } // shared ok for A
43 if rl_slug_guard(kB, "sharedbook" as *u8) != 1 { t0 = 0 } // shared ok for B
44 if rl_slug_guard(kA, "u_elder_aa11bb22_mymanga" as *u8) != 1 { t0 = 0 } // A's personal ok for A
45 if rl_slug_guard(kB, "u_elder_aa11bb22_mymanga" as *u8) != 0 { t0 = 0 } // A's personal DENIED for B
46 if rl_slug_guard(kA, "u_elder_aa11bb2_x" as *u8) != 0 { t0 = 0 } // ukey PREFIX (not whole) DENIED
47 if rl_may_access(kA, "reader/sharedbook/cbx.json" as *u8) != 1 { t0 = 0 }
48 if rl_may_access(kA, "reader/u_elder_aa11bb22_mymanga/page000.jpg" as *u8) != 1 { t0 = 0 }
49 if rl_may_access(kB, "reader/u_elder_aa11bb22_mymanga/page000.jpg" as *u8) != 0 { t0 = 0 }
50 if rl_may_access(kA, "reader/u_elder_aa11bb22_mymanga/../brad/x" as *u8) != 0 { t0 = 0 } // traversal
51 pass = pass + grow("T0 rl_slug_guard + rl_may_access: A ok / B denied / prefix / shared / traversal\x00" as *u8, t0)
52
53 // ---- T1 add personal + idempotent ----
54 g_unlink("knowledge/staging/media/idx_book_personal_elder_aa11bb22.wsl" as *u8)
55 let add1: i64 = rl_add_personal(kA, "mymanga" as *u8, "My Secret Manga" as *u8, 15)
56 let add2: i64 = rl_add_personal(kA, "mymanga" as *u8, "My Secret Manga" as *u8, 15)
57 var t1: i64 = 0
58 let ib: *u8 = sys_mmap(4096)
59 let inn: i64 = g_read("knowledge/staging/media/idx_book_personal_elder_aa11bb22.wsl" as *u8, ib, 4096)
60 if add1 == 1 { if add2 == 0 { if inn > 0 { if g_has(ib, inn, "u_elder_aa11bb22_mymanga\tMy Secret Manga" as *u8) == 1 { if g_exists("knowledge/staging/media/reader/u_elder_aa11bb22_mymanga" as *u8) == 1 { t1 = 1 } } } } }
61 pass = pass + grow("T1 rl_add_personal -> index row (full slug) + dir + idempotent\x00" as *u8, t1)
62
63 // ---- T2 list isolation ----
64 let lb: *u8 = sys_mmap(8192)
65 let ln: i64 = rl_list_personal_json(kA, lb, 8192)
66 var t2: i64 = 0
67 if g_has(lb, ln, "\"slug\":\"u_elder_aa11bb22_mymanga\"" as *u8) == 1 { if g_has(lb, ln, "My Secret Manga" as *u8) == 1 {
68 let lb2: *u8 = sys_mmap(8192); let ln2: i64 = rl_list_personal_json(kB, lb2, 8192)
69 if g_has(lb2, ln2, "mymanga" as *u8) == 0 { if g_has(lb2, ln2, "\"items\":[]" as *u8) == 1 { t2 = 1 } }
70 } }
71 pass = pass + grow("T2 list_personal(A) shows it; list_personal(B) EMPTY\x00" as *u8, t2)
72
73 // ---- T3 real fixture path guard ----
74 g_mkdir("knowledge/staging/media/reader/u_elder_aa11bb22_mymanga" as *u8)
75 g_wr("knowledge/staging/media/reader/u_elder_aa11bb22_mymanga/cbx.json" as *u8, "{\"pages\":[{\"idx\":0,\"file\":\"page000.jpg\"}]}" as *u8, 43)
76 var t3: i64 = 0
77 if rl_may_access(kA, "reader/u_elder_aa11bb22_mymanga/cbx.json" as *u8) == 1 { if rl_may_access(kB, "reader/u_elder_aa11bb22_mymanga/cbx.json" as *u8) == 0 { t3 = 1 } }
78 pass = pass + grow("T3 guard REAL fixture paths (A yes / B no)\x00" as *u8, t3)
79
80 // ---- T4 promote ----
81 g_unlink("knowledge/staging/media/idx_book_shared.wsl" as *u8)
82 g_unlink("knowledge/staging/media/reader/mymanga/cbx.json" as *u8)
83 let pr: i64 = rl_promote_to_shared(kA, "u_elder_aa11bb22_mymanga" as *u8)
84 var t4: i64 = 0
85 if pr == 1 {
86 if g_exists("knowledge/staging/media/reader/mymanga/cbx.json" as *u8) == 1 {
87 if g_exists("knowledge/staging/media/reader/u_elder_aa11bb22_mymanga/cbx.json" as *u8) == 0 {
88 let sib: *u8 = sys_mmap(1024); let sin: i64 = g_read("knowledge/staging/media/idx_book_shared.wsl" as *u8, sib, 1024)
89 if sin > 0 { if g_has(sib, sin, "mymanga" as *u8) == 1 { t4 = 1 } }
90 }
91 }
92 }
93 pass = pass + grow("T4 promote: u_<kA>_mymanga -> reader/mymanga + shared idx + source gone\x00" as *u8, t4)
94
95 // ---- T5 NEG promote ----
96 var t5: i64 = 0
97 let prn: i64 = rl_promote_to_shared(kA, "u_elder_aa11bb22_nosuch" as *u8) // missing -> 0
98 // recreate personal + owner-mismatch + shared-exists
99 g_mkdir("knowledge/staging/media/reader/u_elder_aa11bb22_mymanga" as *u8)
100 g_wr("knowledge/staging/media/reader/u_elder_aa11bb22_mymanga/cbx.json" as *u8, "{}" as *u8, 2)
101 let prB: i64 = rl_promote_to_shared(kB, "u_elder_aa11bb22_mymanga" as *u8) // B not owner -> -1
102 let prc: i64 = rl_promote_to_shared(kA, "u_elder_aa11bb22_mymanga" as *u8) // shared exists -> -1
103 if prn == 0 { if prB == 0 - 1 { if prc == 0 - 1 { t5 = 1 } } }
104 pass = pass + grow("T5 NEG promote: missing->0 ; not-owner->-1 ; shared-exists->-1\x00" as *u8, t5)
105
106 gw("pass=" as *u8); gn(pass); gw("/6\n" as *u8)
107 if pass == 6 { gw("verdict=GREEN (flat-slug shared/personal: owner-in-slug isolation + per-user index + owner-only promote, fail-closed)\n" as *u8); sys_exit(0); return 0 }
108 gw("verdict=RED\n" as *u8); sys_exit(1); return 1
109}