code wiki / _hdl_build / nx_hr_entitle.nx
nx_hr_entitle.nx source
↩ module page · 163 lines · 10073 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 }
43func he_ent_count(prefix: *u8) -> i64 {
44 let h: *i64=ss_open(prefix); if (h as i64)==0 { return 0 }
45 let pp: *i64=sys_mmap(16) as *i64; let ll: *i64=sys_mmap(16) as *i64
46 if ss_hget(h, "ent:count" as *u8, pp, ll) != 1 { return 0 }
47 return he_atoi_n(pp[0] as *u8, ll[0])
48}
49func he_ent_segid(key: *u8, label: *u8, url: *u8) -> i64 {
50 let b: *u8=sys_mmap(K_MAGIC_1024); var o: i64=0
51 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
52 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
53 var k: i64=0; while url[k]!=(0 as u8){b[o]=url[k];o=o+1;k=k+1}
54 let dig: *u8=sys_mmap(32); sha256_digest(b, o, dig)
55 var v: i64=0; var m: i64=0; while m<7 { v=(v<<8)|((dig[m] as i64)&255); m=m+1 } return v
56}
57// GRANT an entitlement (key,label,url) into the seg_store: append the record + bump the count, in one atomic commit.
58// IDEMPOTENT: a re-grant of the identical triple is a no-op (re-provisioning is safe, rule #10).
59func he_ent_put(prefix: *u8, key: *u8, label: *u8, url: *u8) -> i64 {
60 if he_ent_has(prefix, key, label, url)==1 { return 0 }
61 let n: i64=he_ent_count(prefix)
62 let keys: *i64=sys_mmap(8*4) as *i64; let vals: *i64=sys_mmap(8*4) as *i64
63 keys[0]="key" as *u8 as i64; vals[0]=key as i64
64 keys[1]="label" as *u8 as i64; vals[1]=label as i64
65 keys[2]="url" as *u8 as i64; vals[2]=url as i64
66 let buf: *u8=sys_mmap(K_MAGIC_4096); let blen: i64=canon_encode(keys, vals, 3, buf)
67 let ik: *u8=sys_mmap(32); let ikl: i64=he_idx_key(n, ik); ik[ikl]=0 as u8
68 let cv: *u8=sys_mmap(28); let cl: i64=he_itoa(n+1, cv)
69 let w: *i64=ss_begin(); ss_add(w, 1, ik, buf, blen); ss_add(w, 1, "ent:count" as *u8, cv, cl)
70 ss_commit(prefix, w, he_ent_segid(key, label, url))
71 return 0
72}
73func he_ent_get(prefix: *u8, i: i64, ok: *i64, ov: *i64, maxf: i64) -> i64 {
74 let ik: *u8=sys_mmap(32); let ikl: i64=he_idx_key(i, ik); ik[ikl]=0 as u8
75 let h: *i64=ss_open(prefix); if (h as i64)==0 { return 0 }
76 let pp: *i64=sys_mmap(16) as *i64; let ll: *i64=sys_mmap(16) as *i64
77 if ss_hget(h, ik, pp, ll) != 1 { return 0 }
78 return canon_decode(pp[0] as *u8, ll[0], ok, ov, maxf)
79}
80func 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 }
81// 1 iff the EXACT (key,label,url) entitlement already exists (dedup for idempotent grants).
82func he_ent_has(prefix: *u8, key: *u8, label: *u8, url: *u8) -> i64 {
83 let n: i64=he_ent_count(prefix); var i: i64=0
84 let ok: *i64=sys_mmap(16*8) as *i64; let ov: *i64=sys_mmap(16*8) as *i64
85 while i < n {
86 let nf: i64=he_ent_get(prefix, i, ok, ov, 16)
87 if nf > 0 {
88 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)
89 if (k as i64)!=0 { if (l as i64)!=0 { if (u as i64)!=0 {
90 if he_streq(k, key)==1 { if he_streq(l, label)==1 { if he_streq(u, url)==1 { return 1 } } }
91 } } }
92 }
93 i=i+1
94 }
95 return 0
96}
97
98// COUNT the entitlements a user with the given SUPER bit + handle is entitled to (iterates the ent seg_store).
99func he_count_super(super: i64, handle: *u8, hn: i64, ent_prefix: *u8) -> i64 {
100 let n: i64=he_ent_count(ent_prefix); var cnt: i64=0; var i: i64=0
101 let ok: *i64=sys_mmap(16*8) as *i64; let ov: *i64=sys_mmap(16*8) as *i64
102 while i < n {
103 let nf: i64=he_ent_get(ent_prefix, i, ok, ov, 16)
104 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 } } }
105 i=i+1
106 }
107 return cnt
108}
109func he_count_access(hr_store: *u8, realm: *u8, realm_n: i64, handle: *u8, hn: i64, ent_prefix: *u8) -> i64 {
110 return he_count_super(he_super_of(hr_store, realm, realm_n, handle, hn), handle, hn, ent_prefix)
111}
112
113// 1 iff (owner/super OR an entitlement keyed "*"/this-handle) grants the SPECIFIC area `url`. The per-area authZ
114// gate for "single login + approve-by-area" (operator 2026-06-24): a user reaches /gen only if entitled to "/gen"
115// (or is the owner). Deny-by-default. Mirrors he_count_super's iteration. license_tier: ORIGINAL
116func he_has_access(super: i64, handle: *u8, hn: i64, ent_prefix: *u8, url: *u8) -> i64 {
117 if super == 1 { return 1 }
118 let n: i64=he_ent_count(ent_prefix); var i: i64=0
119 let ok: *i64=sys_mmap(16*8) as *i64; let ov: *i64=sys_mmap(16*8) as *i64
120 while i < n {
121 let nf: i64=he_ent_get(ent_prefix, i, ok, ov, 16)
122 if nf > 0 {
123 let key: *u8=he_ent_field(ok, ov, nf, "key" as *u8)
124 let u: *u8=he_ent_field(ok, ov, nf, "url" as *u8)
125 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 } } } }
126 }
127 i=i+1
128 }
129 return 0
130}
131func he_has_access_realm(hr_store: *u8, realm: *u8, realm_n: i64, handle: *u8, hn: i64, ent_prefix: *u8, url: *u8) -> i64 {
132 return he_has_access(he_super_of(hr_store, realm, realm_n, handle, hn), handle, hn, ent_prefix, url)
133}
134
135// EMIT the user's entitled links as JSON: {"handle":"H","super":S,"links":[{"label":"L","url":"U"},...]}.
136func he_emit_super(super: i64, handle: *u8, hn: i64, ent_prefix: *u8, out: *u8, cap: i64) -> i64 {
137 var o: i64 = 0
138 o = hr_puts(out, o, "{\"handle\":\"" as *u8); o = he_catb(out, o, handle, hn)
139 o = hr_puts(out, o, "\",\"super\":" as *u8); o = hr_putn(out, o, super)
140 o = hr_puts(out, o, ",\"links\":[" as *u8)
141 let n: i64=he_ent_count(ent_prefix); var first: i64=1; var i: i64=0
142 let ok: *i64=sys_mmap(16*8) as *i64; let ov: *i64=sys_mmap(16*8) as *i64
143 while i < n {
144 let nf: i64=he_ent_get(ent_prefix, i, ok, ov, 16)
145 if nf > 0 {
146 let key: *u8=he_ent_field(ok, ov, nf, "key" as *u8)
147 if (key as i64)!=0 { if he_include_key(super, key, handle, hn)==1 {
148 let label: *u8=he_ent_field(ok, ov, nf, "label" as *u8)
149 let url: *u8=he_ent_field(ok, ov, nf, "url" as *u8)
150 if first == 0 { out[o]=44 as u8; o=o+1 }
151 o = hr_puts(out, o, "{\"label\":\"" as *u8); if (label as i64)!=0 { o=hr_puts(out, o, label) }
152 o = hr_puts(out, o, "\",\"url\":\"" as *u8); if (url as i64)!=0 { o=hr_puts(out, o, url) }
153 o = hr_puts(out, o, "\"}" as *u8); first = 0
154 } }
155 }
156 i=i+1
157 }
158 o = hr_puts(out, o, "]}" as *u8)
159 return o
160}
161func he_emit_access(hr_store: *u8, realm: *u8, realm_n: i64, handle: *u8, hn: i64, ent_prefix: *u8, out: *u8, cap: i64) -> i64 {
162 return he_emit_super(he_super_of(hr_store, realm, realm_n, handle, hn), handle, hn, ent_prefix, out, cap)
163}