code wiki / _hdl_build / nx_apistack_ratelimit_gate.nx
nx_apistack_ratelimit_gate.nx source
↩ module page · 53 lines · 3599 B
1import "nx_gate_gn.nx"
2// nx_apistack_ratelimit_gate.nx -- hermetic gate for CAP-API-RATELIMIT. Proves the deterministic token-bucket:
3// burst up to cap then 429, refill over elapsed time, cap ceiling on long idle, data-driven per-key quotas, and
4// bit-identical decisions for identical inputs. Sovereign: nx_syscalls + nx_apistack_ratelimit. expect_exit: 0
5import "nx_syscalls.nx"
6import "nx_apistack_ratelimit.nx"
7
8func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
9func g_app(buf: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){buf[off+i]=s[i];i=i+1} return off+i }
10
11func main(argc: i64, argv: *i64) -> i64 {
12 gp("=== nx_apistack_ratelimit_gate (deterministic token-bucket 429) ===\n" as *u8)
13 var pass: i64 = 0; var fail: i64 = 0
14
15 // T1 burst up to cap=5 (rate 1/s), then 429
16 let st: *i64 = sys_mmap(16) as *i64; st[0]=5; st[1]=100
17 var allows: i64 = 0; var i: i64 = 0
18 while i < 5 { allows = allows + rl_step(st, 5, 1, 100, 1); i = i + 1 }
19 let deny6: i64 = rl_step(st, 5, 1, 100, 1)
20 if allows == 5 { if deny6 == 0 { pass=pass+1; gp(" T1 burst 5 allow then 429 PASS\n" as *u8) } else { fail=fail+1; gp(" T1 FAIL 6th not denied\n" as *u8) } } else { fail=fail+1; gp(" T1 FAIL allows=" as *u8); gn(allows); gp("\n" as *u8) }
21
22 // T2 refill over 3s -> allow again
23 let a2: i64 = rl_step(st, 5, 1, 103, 1)
24 if a2 == 1 { pass=pass+1; gp(" T2 refill after 3s -> allow PASS\n" as *u8) } else { fail=fail+1; gp(" T2 FAIL\n" as *u8) }
25
26 // T3 long idle -> tokens cap at cap (not unbounded): after now=1000, exactly cap available
27 let st3: *i64 = sys_mmap(16) as *i64; st3[0]=0; st3[1]=100
28 rl_step(st3, 5, 1, 1000, 0) // cost 0 just refills; elapsed 900*1 capped at 5
29 if st3[0] == 5 { pass=pass+1; gp(" T3 long-idle refill CAPPED at cap=5 PASS\n" as *u8) } else { fail=fail+1; gp(" T3 FAIL tokens=" as *u8); gn(st3[0]); gp("\n" as *u8) }
30
31 // T4 data-driven quota from ratelimits.conf
32 let conf: *u8 = sys_mmap(128); var cn: i64 = 0
33 cn = g_app(conf, cn, "shard-a" as *u8); conf[cn]=9 as u8; cn=cn+1
34 cn = g_app(conf, cn, "10" as *u8); conf[cn]=9 as u8; cn=cn+1
35 cn = g_app(conf, cn, "2" as *u8); conf[cn]=10 as u8; cn=cn+1
36 let cfd: i64 = sys_openat_wr("/tmp/rl_conf.tsv" as *u8, 0x1a4); if cfd >= 0 { sys_write(cfd, conf, cn); sys_close(cfd) }
37 let ocap: *i64 = sys_mmap(8) as *i64; let orate: *i64 = sys_mmap(8) as *i64
38 let found: i64 = rl_config("/tmp/rl_conf.tsv" as *u8, "shard-a" as *u8, 7, ocap, orate)
39 if found == 1 { if ocap[0]==10 { if orate[0]==2 { pass=pass+1; gp(" T4 quota-as-data (shard-a cap=10 rate=2) PASS\n" as *u8) } } }
40 if found != 1 { fail=fail+1; gp(" T4 FAIL config miss\n" as *u8) }
41 else { if ocap[0]!=10 { fail=fail+1; gp(" T4 FAIL cap=" as *u8); gn(ocap[0]); gp("\n" as *u8) } }
42
43 // T5 determinism: identical inputs -> identical decision
44 let sa: *i64 = sys_mmap(16) as *i64; sa[0]=3; sa[1]=50
45 let sb: *i64 = sys_mmap(16) as *i64; sb[0]=3; sb[1]=50
46 let da: i64 = rl_step(sa, 5, 1, 52, 4)
47 let db: i64 = rl_step(sb, 5, 1, 52, 4)
48 if da == db { if sa[0]==sb[0] { pass=pass+1; gp(" T5 identical inputs -> identical decision + state PASS\n" as *u8) } else { fail=fail+1; gp(" T5 FAIL state diverged\n" as *u8) } } else { fail=fail+1; gp(" T5 FAIL decision diverged\n" as *u8) }
49
50 gp("RESULT pass=" as *u8); gn(pass); gp(" fail=" as *u8); gn(fail)
51 if fail == 0 { gp(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
52 gp(" verdict=RED\n" as *u8); sys_exit(1); return 1
53}