nx_osattest.nx
buildroot/runtime/nx_osattest.nx
about
nx_osattest.nx -- LR6: NISHIOS + NISHI BROWSER LANGUAGE-RING INHERITANCE ATTESTATION.
WHAT IT ANSWERS. Chromium's Rule of 2 forbids combining untrustworthy input, an unsafe language and
high privilege; the incumbents discharge it by SANDBOXING AROUND their language. A kernel-up
single-language stack can discharge the unsafe-language leg directly -- but only if that is MEASURED,
not asserted. This organ rebuilds the NishiOS kernel closure and the Nishi Browser closure under each
DECLARED safety mode of a named compiler and writes a receipt both compare pages cite.
IT IS A MEASUREMENT ORGAN. It never edits the compiler, the kernel or the browser; it never
assembles, never runs a produced binary, and never promotes anything. Its only writes are the receipt
and its own scratch under the conf's scratch_dir.
A REFUSAL IS A FINDING, NOT A FAILURE OF THIS ORGAN. A closure that will not compile under an
enforcing mode is exactly the Rule-of-2 evidence the rung exists to produce, so REFUSED cells are DATA
and leave the exit code at 0. What DOES move the exit code is an attestation that cannot be trusted:
a subject whose source does not resolve (3), or one that will not build under the DEFAULT mode (1), in
which case nothing measured under a mode is attributable to that mode.
THE HAZARD THAT SHAPES THE WHOLE DESIGN. nx_compile_x86's long-flag dispatch keys on ONE BYTE
(arg[2]). An unrecognised long flag is therefore SILENTLY IGNORED and the compile still returns 0 --
so an attester that trusted a flag NAME would publish ATTESTED for a mode enforcing nothing, and its
green would be indistinguishable from a real one. Every axis is therefore proven LIVE first, from
BOTH sides, against the compiler under test: for a refuse-kind mode the hazard fixture must be REFUSED
with the DECLARED rule slug in stderr while a clean fixture is still ACCEPTED; for the emit-kind crash
guard the marker must appear by default and vanish under the opt-out. An axis that cannot be proven
live is UNOBSERVABLE -- neither clean nor refused -- and is NAMED in the receipt beside the
denominator, because an abstention nobody reads is a lie nobody told.
COMPOSED, NOT RE-IMPLEMENTED: nx_ccgate_lib (the ONE compiler-spawn driver), nx_incclosure_lib (the
ONE name->path resolver and hex encoder), nx_lineconf_lib (the ONE line-anchored conf reader),
nx_closurehash (the ONE closure enumerator, FORKED for provenance). Every path, flag, fixture and
rule slug is a row in knowledge/lang_attest.conf (rule 11).
RESOURCE ENVELOPE. Allocations are mmap'd once and live for the process (arena doctrine, no free):
tables sized from the conf's own counts, one receipt buffer DERIVED from those counts, one digit
scratch. Per run it spawns 4 compiles per refuse-axis and 2 per emit-axis (all on sub-2 KB fixtures),
plus 1 baseline + one-per-live-refuse-axis compiles per closure and one nx_closurehash fork per
closure. The emit axis costs NO extra compile: it reads the baseline assembly already produced.
Scratch .s files are REUSED in place (sys_openat_wr is O_TRUNC), so peak scratch is one baseline .s
plus one mode .s, never one per cell.
dependencies 5 imports · 0 importers
imports: nx_syscalls.nxnx_sha256.nxnx_ccgate_lib.nxnx_lineconf_lib.nxnx_incclosure_lib.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 55 | const OA_MAXC: i64 = 16 |
| 56 | const OA_MAXA: i64 = 16 |
| 57 | const OA_FW: i64 = 256 // per-field slot width (the longest declared rule slug is 52 bytes) |
| 58 | const OA_PW: i64 = 1024 // path width; mirrors ICL_PATHW so a resolved path can never overflow |
| 59 | const OA_KEYW: i64 = 64 |
| 60 | const OA_ROWW: i64 = 640 // receipt bytes budgeted per emitted row; the TOTAL cap is derived below |
| 61 | const OA_HDRW: i64 = 8192 // header + footer allowance in the same derivation |
| 62 | const OA_DIGW: i64 = 32 |
| 63 | const OA_WORD: i64 = 8 |
| 64 | const OA_DIG64: i64 = 64 |
| 66 | const OA_SP: i64 = 32 |
| 67 | const OA_NL: i64 = 10 |
| 68 | const OA_MINUS: i64 = 45 |
| 69 | const OA_ZERO: i64 = 48 |
| 70 | const OA_NINE: i64 = 57 |
| 71 | const OA_DEC: i64 = 10 |
| 72 | const OA_SHA_HEXW: i64 = 80 |
| 75 | const OA_ATTESTED: i64 = 0 |
| 76 | const OA_REFUSED: i64 = 1 |
| 77 | const OA_GUARD_ABSENT: i64 = 2 |
| 78 | const OA_UNOBSERVABLE: i64 = 3 |
| 79 | const OA_BASELINE_FAIL: i64 = 4 |
| 80 | const OA_SUBJECT_ABSENT: i64 = 5 |
| 82 | const OA_EXIT_OK: i64 = 0 |
| 83 | const OA_EXIT_BASELINE: i64 = 1 |
| 84 | const OA_EXIT_USAGE: i64 = 2 |
| 85 | const OA_EXIT_UNPROVEN: i64 = 3 |
| 88 | const OA_SUB_OK: i64 = 0 |
| 89 | const OA_SUB_BASE: i64 = 1 |
| 90 | const OA_SUB_ABSENT: i64 = 2 |
functions
| 93 | func oa_digits() -> *u8 |
| 98 | func oa_slot(b: *u8, i: i64, w: i64) -> *u8 { return ((b as i64) + i * w) as *u8 } called by 1: main |
| 102 | func oa_err(s: *u8) -> i64 { sys_write(2, s, icl_len(s)); return 0 } |
| 106 | func oa_set(dst: *u8, s: *u8) -> i64 |
| 113 | func oa_addn(rb: *u8, ro: i64, v: i64) -> i64 |
| 127 | func oa_key(dst: *u8, pfx: *u8, idx: i64, sfx: *u8) -> i64 |
| 136 | func oa_join(a: *u8, b: *u8) -> *u8 |
| 144 | func oa_is_undeclared(s: *u8) -> i64 { return icl_seq(s, "_UNDECLARED_" as *u8) } |
| 149 | func oa_cc(cc: *u8, flag: *u8, src: *u8, sout: *u8, eout: *u8) -> i64 |
| 156 | func oa_closurehash(elf: *u8, target: *u8, root: *u8, outp: *u8, errp: *u8) -> i64 |
| 171 | func oa_word_at(b: *u8, n: i64, o: i64, out: *u8, cap: i64) -> i64 called by 1: main |
| 193 | func oa_num_after(b: *u8, n: i64, from: i64, key: *u8) -> i64 |
| 236 | func oa_state_name(s: i64) -> *u8 called by 1: main |
| 245 | func main(argc: i64, argv: *i64) -> i64 |