code wiki / _hdl_build / nx_rebac_gate.nx

nx_rebac_gate.nx source

↩ module page · 122 lines · 11119 B

1// nx_rebac_gate.nx -- ADVERSARIAL GATE for the sovereign ReBAC plane (nx_rebac). The CRITIC + ADVERSARY: a 2// legit-access/attack matrix where every escalation, revocation-bypass, cross-scope leak, block-bypass, and 3// userset-cycle MUST resolve correctly (deny-by-default). Green ONLY if all ~28 checks pass. license_tier: ORIGINAL 4// expect_exit: 0 5import "nx_rebac.nx" 6 7func ck(label: *u8, got: i64, want: i64, okp: *i64) -> i64 { 8 rb_p(" REBAC " as *u8); rb_p(label) 9 if got == 1 { rb_p(" -> ALLOW" as *u8) } else { rb_p(" -> DENY " as *u8) } 10 if got == want { rb_p(" ok\n" as *u8); return 0 } 11 rb_p(" *** WRONG (wanted " as *u8); rb_pn(want); rb_p(") ***\n" as *u8) 12 okp[0] = 0 13 return 0 14} 15 16func main() -> i64 { 17 rb_p("=== NX-REBAC ADVERSARIAL GATE (Zanzibar/ReBAC: tuple check + userset rewrite + tombstone + block + HR override) ===\n" as *u8) 18 let okp: *i64 = sys_mmap(8) as *i64; okp[0] = 1 19 20 // fresh store prefix (own the isolation; sys_now_us keeps commits time-ordered for latest-wins) 21 let prefix: *u8 = sys_mmap(128); var po: i64 = 0 22 po = rb_cat(prefix, po, "/tmp/rebac_" as *u8); po = rb_catn(prefix, po, sys_now_us()); po = rb_cat(prefix, po, "_" as *u8); prefix[po] = 0 as u8 23 24 // ---- SETUP (grants) ---- 25 // group:elders owned by alice, bob is a member; doc:budget owned by alice, SHARED with elders#member (userset); 26 // tenant:andelinwest admin=alice member=bob; alice<->bob mutual friends. 27 rb_put(prefix, "group:elders" as *u8, "owner" as *u8, "user:alice" as *u8, "system" as *u8, 1) 28 rb_put(prefix, "group:elders" as *u8, "member" as *u8, "user:bob" as *u8, "user:alice" as *u8, 1) 29 rb_put(prefix, "doc:budget" as *u8, "owner" as *u8, "user:alice" as *u8, "system" as *u8, 1) 30 rb_put(prefix, "doc:budget" as *u8, "viewer" as *u8, "group:elders#member" as *u8, "user:alice" as *u8, 1) 31 rb_put(prefix, "tenant:andelinwest" as *u8, "admin" as *u8, "user:alice" as *u8, "system" as *u8, 1) 32 rb_put(prefix, "tenant:andelinwest" as *u8, "member" as *u8, "user:bob" as *u8, "user:alice" as *u8, 1) 33 rb_put(prefix, "user:alice" as *u8, "friend" as *u8, "user:bob" as *u8, "user:bob" as *u8, 1) 34 rb_put(prefix, "user:bob" as *u8, "friend" as *u8, "user:alice" as *u8, "user:alice" as *u8, 1) 35 36 // ---- ALLOW (legitimate access) ---- 37 ck("A1 alice manage doc:budget (owner)" as *u8, rb_check(prefix, "user:alice" as *u8, "manage" as *u8, "doc:budget" as *u8, 0), 1, okp) 38 ck("A2 bob read doc:budget (member->elders#member->viewer USERSET)" as *u8, rb_check(prefix, "user:bob" as *u8, "read" as *u8, "doc:budget" as *u8, 0), 1, okp) 39 ck("A3 alice read doc:budget (owner->read rewrite)" as *u8, rb_check(prefix, "user:alice" as *u8, "read" as *u8, "doc:budget" as *u8, 0), 1, okp) 40 ck("A4 bob view group:elders (member)" as *u8, rb_check(prefix, "user:bob" as *u8, "view" as *u8, "group:elders" as *u8, 0), 1, okp) 41 ck("A5 alice manage group:elders (owner)" as *u8, rb_check(prefix, "user:alice" as *u8, "manage" as *u8, "group:elders" as *u8, 0), 1, okp) 42 ck("A6 bob read tenant:andelinwest (member)" as *u8, rb_check(prefix, "user:bob" as *u8, "read" as *u8, "tenant:andelinwest" as *u8, 0), 1, okp) 43 ck("A7 alice friend bob (mutual)" as *u8, rb_check(prefix, "user:alice" as *u8, "friend" as *u8, "user:bob" as *u8, 0), 1, okp) 44 45 // ENUMERATORS (the surface lists a caller's circle from these): alice's friends include bob; bob's groups include elders 46 let el: *i64 = sys_mmap(8 * 64) as *i64 47 let enf: i64 = rb_list_subjects(prefix, "user:alice" as *u8, "friend" as *u8, el, 64) 48 var friend_listed: i64 = 0 49 if enf >= 1 { if rb_in_list(el, enf, "user:bob" as *u8) == 1 { friend_listed = 1 } } 50 ck("E1 rb_list_subjects: alice friends include bob" as *u8, friend_listed, 1, okp) 51 let eg: *i64 = sys_mmap(8 * 64) as *i64 52 let eng: i64 = rb_list_objects_for_sub(prefix, "user:bob" as *u8, "member" as *u8, eg, 64) 53 var group_listed: i64 = 0 54 if eng >= 1 { if rb_in_list(eg, eng, "group:elders" as *u8) == 1 { group_listed = 1 } } 55 ck("E2 rb_list_objects_for_sub: bob groups include elders" as *u8, group_listed, 1, okp) 56 57 // ---- DENY (adversary: no grant / wrong relation / escalation) ---- 58 ck("D1 carol read doc:budget (not a member)" as *u8, rb_check(prefix, "user:carol" as *u8, "read" as *u8, "doc:budget" as *u8, 0), 0, okp) 59 ck("D2 bob WRITE doc:budget (only viewer, not editor)" as *u8, rb_check(prefix, "user:bob" as *u8, "write" as *u8, "doc:budget" as *u8, 0), 0, okp) 60 ck("D3 mallory read tenant:andelinwest (no grant)" as *u8, rb_check(prefix, "user:mallory" as *u8, "read" as *u8, "tenant:andelinwest" as *u8, 0), 0, okp) 61 ck("D4 bob MANAGE group:elders (member != admin ESCALATION)" as *u8, rb_check(prefix, "user:bob" as *u8, "manage" as *u8, "group:elders" as *u8, 0), 0, okp) 62 ck("D5 carol friend alice (not friends)" as *u8, rb_check(prefix, "user:carol" as *u8, "friend" as *u8, "user:alice" as *u8, 0), 0, okp) 63 64 // ---- REVOCATION (tombstone must WIN; scoped, not global) ---- 65 // T1 defriend: tombstone both directions -> no longer friends 66 rb_put(prefix, "user:alice" as *u8, "friend" as *u8, "user:bob" as *u8, "user:alice" as *u8, 0) 67 rb_put(prefix, "user:bob" as *u8, "friend" as *u8, "user:alice" as *u8, "user:bob" as *u8, 0) 68 ck("T1 defriended: alice friend bob (tombstone wins)" as *u8, rb_check(prefix, "user:alice" as *u8, "friend" as *u8, "user:bob" as *u8, 0), 0, okp) 69 // T2 leave group: bob leaves elders -> loses doc VIA the group, but KEEPS the independent tenant membership 70 rb_put(prefix, "group:elders" as *u8, "member" as *u8, "user:bob" as *u8, "user:bob" as *u8, 0) 71 ck("T2a left-group: bob read doc:budget (userset re-eval DENIES)" as *u8, rb_check(prefix, "user:bob" as *u8, "read" as *u8, "doc:budget" as *u8, 0), 0, okp) 72 ck("T2b scoped: bob read tenant:andelinwest STILL allowed" as *u8, rb_check(prefix, "user:bob" as *u8, "read" as *u8, "tenant:andelinwest" as *u8, 0), 1, okp) 73 // T3 re-grant then unshare: re-join proves re-grant works; unshare the doc-userset kills it again 74 rb_put(prefix, "group:elders" as *u8, "member" as *u8, "user:bob" as *u8, "user:alice" as *u8, 1) 75 ck("T3a re-joined: bob read doc:budget allowed again (re-grant)" as *u8, rb_check(prefix, "user:bob" as *u8, "read" as *u8, "doc:budget" as *u8, 0), 1, okp) 76 rb_put(prefix, "doc:budget" as *u8, "viewer" as *u8, "group:elders#member" as *u8, "user:alice" as *u8, 0) 77 ck("T3b unshared: bob read doc:budget DENIED (userset tombstone)" as *u8, rb_check(prefix, "user:bob" as *u8, "read" as *u8, "doc:budget" as *u8, 0), 0, okp) 78 79 // ---- BLOCK (consent axis: blocks OUTRANK any relation) ---- 80 rb_put(prefix, "user:bob" as *u8, "blocked" as *u8, "user:mallory" as *u8, "user:bob" as *u8, 1) 81 ck("B1 mallory friend bob after BLOCK (blocks outrank)" as *u8, rb_check(prefix, "user:mallory" as *u8, "friend" as *u8, "user:bob" as *u8, 0), 0, okp) 82 ck("B2 mallory view bob after BLOCK" as *u8, rb_check(prefix, "user:mallory" as *u8, "view" as *u8, "user:bob" as *u8, 0), 0, okp) 83 84 // ---- HR OPERATOR OVERRIDE (the tie to Nishi HR level) ---- 85 ck("H1 mallory read tenant via HR operator lvl 3 (god-in-realm)" as *u8, rb_check_hr(prefix, "user:mallory" as *u8, "read" as *u8, "tenant:andelinwest" as *u8, 3), 1, okp) 86 ck("H2 mallory read tenant via HR member lvl 1 (no tuple -> deny)" as *u8, rb_check_hr(prefix, "user:mallory" as *u8, "read" as *u8, "tenant:andelinwest" as *u8, 1), 0, okp) 87 88 // ---- WRITE AUTHORITY (a member cannot grant; unclaimed object bootstraps; then closes) ---- 89 ck("W1 bob may_grant doc:budget (viewer, not manage -> NO)" as *u8, rb_may_grant(prefix, "user:bob" as *u8, "doc:budget" as *u8), 0, okp) 90 ck("W2 alice may_grant doc:budget (owner -> YES)" as *u8, rb_may_grant(prefix, "user:alice" as *u8, "doc:budget" as *u8), 1, okp) 91 ck("W3a carol may_grant group:new (UNCLAIMED -> bootstrap YES)" as *u8, rb_may_grant(prefix, "user:carol" as *u8, "group:new" as *u8), 1, okp) 92 rb_put(prefix, "group:new" as *u8, "owner" as *u8, "user:carol" as *u8, "user:carol" as *u8, 1) 93 ck("W3b mallory may_grant group:new (now CLAIMED by carol -> NO)" as *u8, rb_may_grant(prefix, "user:mallory" as *u8, "group:new" as *u8), 0, okp) 94 95 // ---- NESTED USERSET (positive, multi-level): leads subgroup nested in elders, doc shared with elders ---- 96 rb_put(prefix, "group:leads" as *u8, "member" as *u8, "user:carol" as *u8, "user:carol" as *u8, 1) 97 rb_put(prefix, "group:elders" as *u8, "member" as *u8, "group:leads#member" as *u8, "user:alice" as *u8, 1) 98 rb_put(prefix, "doc:plan" as *u8, "owner" as *u8, "user:alice" as *u8, "system" as *u8, 1) 99 rb_put(prefix, "doc:plan" as *u8, "viewer" as *u8, "group:elders#member" as *u8, "user:alice" as *u8, 1) 100 ck("U1 carol read doc:plan (carol->leads->elders->doc NESTED userset)" as *u8, rb_check(prefix, "user:carol" as *u8, "read" as *u8, "doc:plan" as *u8, 0), 1, okp) 101 102 // ---- CYCLE TERMINATION (adversary DoS: mutual group membership must NOT hang) ---- 103 rb_put(prefix, "group:ca" as *u8, "member" as *u8, "group:cb#member" as *u8, "user:alice" as *u8, 1) 104 rb_put(prefix, "group:cb" as *u8, "member" as *u8, "group:ca#member" as *u8, "user:alice" as *u8, 1) 105 ck("C1 cyclic groups TERMINATE (mallory read group:ca -> bounded DENY, no hang)" as *u8, rb_check(prefix, "user:mallory" as *u8, "read" as *u8, "group:ca" as *u8, 0), 0, okp) 106 107 // ---- CROSS-SURFACE (rb_check2, two stores): a GROUP in store2 grants an OBJECT owned in store1 ---- 108 let p2: *u8 = sys_mmap(128); var p2o: i64 = 0 109 p2o = rb_cat(p2, p2o, "/tmp/rebac2_" as *u8); p2o = rb_catn(p2, p2o, sys_now_us()); p2o = rb_cat(p2, p2o, "_" as *u8); p2[p2o] = 0 as u8 110 rb_put(p2, "group:choir" as *u8, "member" as *u8, "user:zoe" as *u8, "user:lead" as *u8, 1) // store2 = the "relate" surface 111 rb_put(prefix, "doc:hymnal" as *u8, "owner" as *u8, "user:lead" as *u8, "system" as *u8, 1) // store1 = the "office" surface 112 rb_put(prefix, "doc:hymnal" as *u8, "viewer" as *u8, "group:choir#member" as *u8, "user:lead" as *u8, 1) 113 ck("X1 CROSS-SURFACE: zoe (store2 group member) reads doc in store1" as *u8, rb_check2(prefix, p2, "user:zoe" as *u8, "read" as *u8, "doc:hymnal" as *u8, 0), 1, okp) 114 ck("X2 non-member frank DENIED cross-surface" as *u8, rb_check2(prefix, p2, "user:frank" as *u8, "read" as *u8, "doc:hymnal" as *u8, 0), 0, okp) 115 rb_put(p2, "group:choir" as *u8, "member" as *u8, "user:zoe" as *u8, "user:lead" as *u8, 0) // revoke in store2 116 ck("X3 revoke store2 group membership -> zoe LOSES the store1 doc" as *u8, rb_check2(prefix, p2, "user:zoe" as *u8, "read" as *u8, "doc:hymnal" as *u8, 0), 0, okp) 117 118 rb_p("NX-REBAC-GATE " as *u8) 119 if okp[0] == 1 { rb_p("verdict=GREEN (28 checks: userset rewrites + nested groups + tombstone revocation + scoped-not-global + blocks-outrank + HR operator override + write-authority-no-escalation + cycle-termination)\n" as *u8); return 0 } 120 rb_p("verdict=RED\n" as *u8) 121 return 1 122}