code wiki / _hdl_build / nx_hr_entitle.nx

nx_hr_entitle.nx source

↩ module page · 172 lines · 10790 B

1// nx_hr_entitle.nx -- SUPERUSER-BY-CONSTRUCTION entitlement resolution, now on the SOVEREIGN store (operator NO-TSV 2// doctrine [[feedback-no-3rd-party-tsv-sovereign-store]]). Entitlements no longer live in a flat .tsv -- each is a 3// CANON record (key,label,url) in a content-addressed nx_seg_store, enumerated via a count+index ("ent:count" + 4// "ent:<i>"), the proven nx_native_config pattern. Semantics unchanged: 5// * an ACTIVE SUPERADMIN (HR owner, lvl 3) is entitled to EVERY entitlement -- auto-access, zero drift; and 6// * everyone else gets the public ("*") entitlements + the ones keyed to their own handle (deny-by-default). 7// Superadmin status comes from the HR SSOT (hra_is_superadmin, now seg_store-backed). Pure resolver. 8// entitlement record fields: key (a handle, or "*" for everyone), label, url 9import "nx_hr_admin.nx" // hra_is_superadmin 10import "nx_hr.nx" // hr_cred_id / hr_puts / hr_putn (derivation + string helpers) 11import "nx_seg_store.nx" // ss_begin / ss_add / ss_commit / ss_open / ss_hget 12import "nx_canon_cid.nx" // canon_encode 13import "nx_uxf_decode.nx" // canon_decode 14import "nx_sha256.nx" // sha256_digest (segid) 15import "nx_syscalls.nx" 16const K_MAGIC_1024: i64 = 1024 17const K_MAGIC_4096: i64 = 4096 18 19func he_memeq(a: *u8, b: *u8, n: i64) -> i64 { var i: i64=0; while i<n { if a[i]!=b[i] { return 0 } i=i+1 } return 1 } 20func he_catb(dst: *u8, off: i64, src: *u8, n: i64) -> i64 { var o: i64=off; var i: i64=0; while i<n { dst[o]=src[i]; o=o+1; i=i+1 } return o } 21func he_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 22func he_streq(a: *u8, b: *u8) -> i64 { var i: i64=0; while 1==1 { let ca: i64=a[i] as i64; let cb: i64=b[i] as i64; if ca!=cb {return 0} if ca==0 {return 1} i=i+1 } return 1 } 23func he_itoa(v: i64, out: *u8) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{out[i]=t[k-1-i];i=i+1} out[k]=0 as u8; return k } 24func he_atoi_n(s: *u8, n: i64) -> i64 { var v: i64=0; var i: i64=0; while i<n { let c: i64=s[i] as i64; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } return v } 25 26// the include predicate on a KEY string: superadmin -> every entitlement; else wildcard "*" or exact-handle key. 27func he_include_key(super: i64, key: *u8, handle: *u8, hn: i64) -> i64 { 28 if super == 1 { return 1 } 29 let kl: i64 = he_slen(key) 30 if kl == 1 { if key[0] == (42 as u8) { return 1 } } // '*' 31 if kl == hn { if he_memeq(key, handle, hn) == 1 { return 1 } } 32 return 0 33} 34// resolve the SUPERADMIN bit for (realm, handle) from the HR SSOT (seg_store-backed). 0 if absent / not active owner. 35func he_super_of(hr_store: *u8, realm: *u8, realm_n: i64, handle: *u8, hn: i64) -> i64 { 36 let cid: *u8 = sys_mmap(96) 37 if hr_cred_id(realm, realm_n, handle, hn, cid) <= 0 { return 0 } 38 return hra_is_superadmin(hr_store, cid, 64) 39} 40 41// ---- the entitlement seg_store: "ent:count" + "ent:<i>" -> canon{key,label,url} ---- 42func he_idx_key(i: i64, out: *u8) -> i64 { let p: *u8="ent:" as *u8; var o: i64=0; while p[o]!=(0 as u8){out[o]=p[o];o=o+1} let k: i64=he_itoa(i, (out as i64 + o) as *u8); return o+k } 43// CLOSE WHAT YOU OPEN (2026-08-18, lane F). ss_open maps EVERY segment of the store (docs + idx + live-doc maps + 44// query scratch); this file opened one handle per call and dropped it -- and he_emit_super calls he_ent_count 45// once and he_ent_get once PER ENTITLEMENT on every /whoami and /access, so a single session heartbeat leaked a 46// dozen full store mappings. Both readers COPY out of the mapping before returning (he_atoi_n reads an int; 47// canon_decode hands back null-terminated copies, nx_uxf_decode), so ss_close right after the read is sound. 48func he_ent_count(prefix: *u8) -> i64 { 49 let h: *i64=ss_open(prefix); if (h as i64)==0 { return 0 } 50 let pp: *i64=sys_mmap(16) as *i64; let ll: *i64=sys_mmap(16) as *i64 51 var n: i64=0 52 if ss_hget(h, "ent:count" as *u8, pp, ll) == 1 { n=he_atoi_n(pp[0] as *u8, ll[0]) } 53 ss_close(h) 54 return n 55} 56func he_ent_segid(key: *u8, label: *u8, url: *u8) -> i64 { 57 let b: *u8=sys_mmap(K_MAGIC_1024); var o: i64=0 58 var i: i64=0; while key[i]!=(0 as u8){b[o]=key[i];o=o+1;i=i+1} b[o]=124 as u8;o=o+1 59 var j: i64=0; while label[j]!=(0 as u8){b[o]=label[j];o=o+1;j=j+1} b[o]=124 as u8;o=o+1 60 var k: i64=0; while url[k]!=(0 as u8){b[o]=url[k];o=o+1;k=k+1} 61 let dig: *u8=sys_mmap(32); sha256_digest(b, o, dig) 62 var v: i64=0; var m: i64=0; while m<7 { v=(v<<8)|((dig[m] as i64)&255); m=m+1 } return v 63} 64// GRANT an entitlement (key,label,url) into the seg_store: append the record + bump the count, in one atomic commit. 65// IDEMPOTENT: a re-grant of the identical triple is a no-op (re-provisioning is safe, rule #10). 66func he_ent_put(prefix: *u8, key: *u8, label: *u8, url: *u8) -> i64 { 67 if he_ent_has(prefix, key, label, url)==1 { return 0 } 68 let n: i64=he_ent_count(prefix) 69 let keys: *i64=sys_mmap(8*4) as *i64; let vals: *i64=sys_mmap(8*4) as *i64 70 keys[0]="key" as *u8 as i64; vals[0]=key as i64 71 keys[1]="label" as *u8 as i64; vals[1]=label as i64 72 keys[2]="url" as *u8 as i64; vals[2]=url as i64 73 let buf: *u8=sys_mmap(K_MAGIC_4096); let blen: i64=canon_encode(keys, vals, 3, buf) 74 let ik: *u8=sys_mmap(32); let ikl: i64=he_idx_key(n, ik); ik[ikl]=0 as u8 75 let cv: *u8=sys_mmap(28); let cl: i64=he_itoa(n+1, cv) 76 let w: *i64=ss_begin(); ss_add(w, 1, ik, buf, blen); ss_add(w, 1, "ent:count" as *u8, cv, cl) 77 ss_commit(prefix, w, he_ent_segid(key, label, url)) 78 return 0 79} 80func he_ent_get(prefix: *u8, i: i64, ok: *i64, ov: *i64, maxf: i64) -> i64 { 81 let ik: *u8=sys_mmap(32); let ikl: i64=he_idx_key(i, ik); ik[ikl]=0 as u8 82 let h: *i64=ss_open(prefix); if (h as i64)==0 { return 0 } 83 let pp: *i64=sys_mmap(16) as *i64; let ll: *i64=sys_mmap(16) as *i64 84 var nf: i64=0 85 if ss_hget(h, ik, pp, ll) == 1 { nf=canon_decode(pp[0] as *u8, ll[0], ok, ov, maxf) } 86 ss_close(h) // canon_decode COPIED the fields out (see he_ent_count); the mapping is not referenced past here 87 return nf 88} 89func he_ent_field(ok: *i64, ov: *i64, nf: i64, name: *u8) -> *u8 { var i: i64=0; while i<nf { if he_streq(ok[i] as *u8, name)==1 { return ov[i] as *u8 } i=i+1 } return 0 as *u8 } 90// 1 iff the EXACT (key,label,url) entitlement already exists (dedup for idempotent grants). 91func he_ent_has(prefix: *u8, key: *u8, label: *u8, url: *u8) -> i64 { 92 let n: i64=he_ent_count(prefix); var i: i64=0 93 let ok: *i64=sys_mmap(16*8) as *i64; let ov: *i64=sys_mmap(16*8) as *i64 94 while i < n { 95 let nf: i64=he_ent_get(prefix, i, ok, ov, 16) 96 if nf > 0 { 97 let k: *u8=he_ent_field(ok, ov, nf, "key" as *u8); let l: *u8=he_ent_field(ok, ov, nf, "label" as *u8); let u: *u8=he_ent_field(ok, ov, nf, "url" as *u8) 98 if (k as i64)!=0 { if (l as i64)!=0 { if (u as i64)!=0 { 99 if he_streq(k, key)==1 { if he_streq(l, label)==1 { if he_streq(u, url)==1 { return 1 } } } 100 } } } 101 } 102 i=i+1 103 } 104 return 0 105} 106 107// COUNT the entitlements a user with the given SUPER bit + handle is entitled to (iterates the ent seg_store). 108func he_count_super(super: i64, handle: *u8, hn: i64, ent_prefix: *u8) -> i64 { 109 let n: i64=he_ent_count(ent_prefix); var cnt: i64=0; var i: i64=0 110 let ok: *i64=sys_mmap(16*8) as *i64; let ov: *i64=sys_mmap(16*8) as *i64 111 while i < n { 112 let nf: i64=he_ent_get(ent_prefix, i, ok, ov, 16) 113 if nf > 0 { let key: *u8=he_ent_field(ok, ov, nf, "key" as *u8); if (key as i64)!=0 { if he_include_key(super, key, handle, hn)==1 { cnt=cnt+1 } } } 114 i=i+1 115 } 116 return cnt 117} 118func he_count_access(hr_store: *u8, realm: *u8, realm_n: i64, handle: *u8, hn: i64, ent_prefix: *u8) -> i64 { 119 return he_count_super(he_super_of(hr_store, realm, realm_n, handle, hn), handle, hn, ent_prefix) 120} 121 122// 1 iff (owner/super OR an entitlement keyed "*"/this-handle) grants the SPECIFIC area `url`. The per-area authZ 123// gate for "single login + approve-by-area" (operator 2026-06-24): a user reaches /gen only if entitled to "/gen" 124// (or is the owner). Deny-by-default. Mirrors he_count_super's iteration. license_tier: ORIGINAL 125func he_has_access(super: i64, handle: *u8, hn: i64, ent_prefix: *u8, url: *u8) -> i64 { 126 if super == 1 { return 1 } 127 let n: i64=he_ent_count(ent_prefix); var i: i64=0 128 let ok: *i64=sys_mmap(16*8) as *i64; let ov: *i64=sys_mmap(16*8) as *i64 129 while i < n { 130 let nf: i64=he_ent_get(ent_prefix, i, ok, ov, 16) 131 if nf > 0 { 132 let key: *u8=he_ent_field(ok, ov, nf, "key" as *u8) 133 let u: *u8=he_ent_field(ok, ov, nf, "url" as *u8) 134 if (key as i64)!=0 { if (u as i64)!=0 { if he_include_key(super, key, handle, hn)==1 { if he_streq(u, url)==1 { return 1 } } } } 135 } 136 i=i+1 137 } 138 return 0 139} 140func he_has_access_realm(hr_store: *u8, realm: *u8, realm_n: i64, handle: *u8, hn: i64, ent_prefix: *u8, url: *u8) -> i64 { 141 return he_has_access(he_super_of(hr_store, realm, realm_n, handle, hn), handle, hn, ent_prefix, url) 142} 143 144// EMIT the user's entitled links as JSON: {"handle":"H","super":S,"links":[{"label":"L","url":"U"},...]}. 145func he_emit_super(super: i64, handle: *u8, hn: i64, ent_prefix: *u8, out: *u8, cap: i64) -> i64 { 146 var o: i64 = 0 147 o = hr_puts(out, o, "{\"handle\":\"" as *u8); o = he_catb(out, o, handle, hn) 148 o = hr_puts(out, o, "\",\"super\":" as *u8); o = hr_putn(out, o, super) 149 o = hr_puts(out, o, ",\"links\":[" as *u8) 150 let n: i64=he_ent_count(ent_prefix); var first: i64=1; var i: i64=0 151 let ok: *i64=sys_mmap(16*8) as *i64; let ov: *i64=sys_mmap(16*8) as *i64 152 while i < n { 153 let nf: i64=he_ent_get(ent_prefix, i, ok, ov, 16) 154 if nf > 0 { 155 let key: *u8=he_ent_field(ok, ov, nf, "key" as *u8) 156 if (key as i64)!=0 { if he_include_key(super, key, handle, hn)==1 { 157 let label: *u8=he_ent_field(ok, ov, nf, "label" as *u8) 158 let url: *u8=he_ent_field(ok, ov, nf, "url" as *u8) 159 if first == 0 { out[o]=44 as u8; o=o+1 } 160 o = hr_puts(out, o, "{\"label\":\"" as *u8); if (label as i64)!=0 { o=hr_puts(out, o, label) } 161 o = hr_puts(out, o, "\",\"url\":\"" as *u8); if (url as i64)!=0 { o=hr_puts(out, o, url) } 162 o = hr_puts(out, o, "\"}" as *u8); first = 0 163 } } 164 } 165 i=i+1 166 } 167 o = hr_puts(out, o, "]}" as *u8) 168 return o 169} 170func he_emit_access(hr_store: *u8, realm: *u8, realm_n: i64, handle: *u8, hn: i64, ent_prefix: *u8, out: *u8, cap: i64) -> i64 { 171 return he_emit_super(he_super_of(hr_store, realm, realm_n, handle, hn), handle, hn, ent_prefix, out, cap) 172}