code wiki / (root) / nx_rebac.nx

nx_rebac.nx

buildroot/runtime/nx_rebac.nx

31064 B549 linesdepth 6pulls 8 transitivereach 20 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_rebac.nx -- SOVEREIGN RELATIONSHIP-BASED ACCESS CONTROL (the Google Zanzibar / ReBAC model), the ONE shared authorization plane for every Nishi surface. PURE LIB (no main): consumers = nx_rebac_gate (adversarial gate) + the surfaces (relate/social/office/project) which import this and call rb_check instead of re-implementing ACLs. WHY: the ecosystem had 3 incompatible authz philosophies (relate tenant-wall `acl:`, project `mem:`, connect in-memory group-roles) + an UNWIRED consent primitive + zero relationship/group permissions. This unifies them: EVERYTHING is a TUPLE (object, relation, subject) persisted in seg_store, and access is a bounded graph walk with userset rewrites -- exactly how Google Docs / GitHub / SpiceDB / OpenFGA decide "can X do Y on Z". friend -> (user:bob, friend, user:alice) [mutual: store both directions] join a group -> (group:elders, member, user:bob) share a doc -> (doc:budget, viewer, user:carol) OR (doc:budget, viewer, group:elders#member) <- userset the tenant wall -> (tenant:andelinwest, admin, user:elderwesto) [subsumes relate acl: + project mem:] block / defriend -> a NEW tuple with cur=0 (tombstone) -- ADDITIVE-ONLY, never delete (rule 13); latest wins. PERMISSIONS derive from RELATIONS via a data-driven REWRITE table (rb_expand): e.g. doc.read = viewer|editor|owner. Ties to NISHI HR: rb_check_hr composes the HR level (ag_uid_to_level / hac_gate) as a realm-scoped operator override -- a site operator (level 3) is god within their realm; everyone else is pure deny-by-default tuples. DENY-BY-DEFAULT everywhere; blocks outrank; bounded recursion (RB_MAXDEPTH) so userset cycles TERMINATE not hang. license_tier: ORIGINAL

dependencies 4 imports · 6 importers

nx_syscalls.nx nx_itoa_lib.nx nx_canon_cid.nx nx_seg_store.nx nx_rebac.nx nx_authz_svc.nx nx_office_serve.nx nx_rebac_gate.nx nx_relate_serve.nx nx_share_convergence_gate.nx nx_suite_share.nx

imports: nx_syscalls.nxnx_itoa_lib.nxnx_canon_cid.nxnx_seg_store.nx

imported by: nx_authz_svc.nxnx_office_serve.nxnx_rebac_gate.nxnx_relate_serve.nxnx_share_convergence_gate.nxnx_suite_share.nx

structs

none

consts

23const RB_MAGIC_2048: i64 = 2048
25const RB_MAXDEPTH: i64 = 8 // Zanzibar bounds check() recursion; a member-of cycle terminates here
26const RB_OPERATOR: i64 = 3 // HR level that is site-operator (god within realm); mirrors HRA_LVL_OWNER

functions

29func rb_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
30func rb_p(s: *u8) -> i64 { sys_write(1, s, rb_slen(s)); return 0 }
called by 2: ckmain calls 2: sys_writerb_slen
35func rb_pn(v: i64) -> i64 { nxi_out(v); return 0 }
called by 2: az_pnck calls 1: nxi_out
36func rb_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i }
37func rb_catn(dst: *u8, off: i64, v: i64) -> i64
44func rb_seq(a: *u8, b: *u8) -> i64
50func rb_kmemeq(b: *u8, off: i64, n: i64, s: *u8) -> i64
called by 2: rb_iskindrb_field calls 1: rb_slen
55func rb_iskind(b: *u8, koff: i64, kl: i64, pfx: *u8) -> i64 { if kl <= 4 { return 0 } return rb_kmemeq(b, koff, 4, pfx) }
57func rb_field(rec: *u8, rl: i64, want: *u8, out: *u8, cap: i64) -> i64
76func rb_otype(obj: *u8, out: *u8, cap: i64) -> i64
called by 2: rb_checkrb_check2
81func rb_has_hash(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { if (s[i] as i64) == 35 { return 1 } i = i + 1 } return 0 }
83func rb_split_userset(s: *u8, gobj: *u8, grel: *u8) -> i64
95func rb_save_tuple(w: *i64, obj: *u8, rel: *u8, sub: *u8, grantor: *u8, cur: i64) -> i64
115func rb_put(prefix: *u8, obj: *u8, rel: *u8, sub: *u8, grantor: *u8, cur: i64) -> i64
123func rb_tuple_current(prefix: *u8, obj: *u8, rel: *u8, sub: *u8) -> i64
160func rb_expand(otype: *u8, perm: *u8, out: *i64, cap: i64) -> i64
called by 2: rb_checkrb_check2 calls 1: rb_seq
207func rb_check(prefix: *u8, sub: *u8, perm: *u8, obj: *u8, depth: i64) -> i64
262func rb_check_hr(prefix: *u8, sub: *u8, perm: *u8, obj: *u8, hr_level: i64) -> i64
called by 1: main calls 1: rb_check
272func rb_tuple_current2(p1: *u8, p2: *u8, obj: *u8, rel: *u8, sub: *u8) -> i64
called by 1: rb_check2 calls 1: rb_tuple_current
277func rb_userset_scan(store: *u8, p1: *u8, p2: *u8, sub: *u8, obj: *u8, rel: *u8, depth: i64) -> i64
312func rb_check2(p1: *u8, p2: *u8, sub: *u8, perm: *u8, obj: *u8, depth: i64) -> i64
332func rb_obj_has_owner(prefix: *u8, obj: *u8) -> i64
361func rb_may_grant(prefix: *u8, grantor: *u8, obj: *u8) -> i64
369func rb_hex(dst: *u8, src: *u8, n: i64) -> i64
called by 1: rb_resolve_handle
382func rb_idx_lookup(idx: *u8, idxlen: i64, uidhex: *u8, uxn: i64, out_h: *u8, cap: i64) -> i64
called by 1: rb_resolve_handle
412func rb_resolve_handle(idxpath: *u8, uid: *u8, uidn: i64, out_h: *u8, cap: i64) -> i64
422func rb_in_list(out: *i64, n: i64, s: *u8) -> i64
429func rb_list_subjects(prefix: *u8, obj: *u8, rel: *u8, out: *i64, cap: i64) -> i64
473func rb_list_subjects_history(prefix: *u8, obj: *u8, rel: *u8, out: *i64, cap: i64) -> i64
514func rb_list_objects_for_sub(prefix: *u8, sub: *u8, rel: *u8, out: *i64, cap: i64) -> i64