nx_measurement_binding_capture_gate.nx source
↩ module page · 127 lines · 6493 B
1// Capture the actual staged owner without changing its command/API contract.
2// Only caller-named exclusive /tmp files are written. Existing board artifacts are compared.
3// license_tier: ORIGINAL; expect_exit: 0
4import "nx_gatekit_lib.nx"
5import "nx_gate_verdict.nx"
6import "nx_estate_path.nx"
7
8const BC_FILE_MODE: i64 = 0x180 // POSIX owner-read/write temporary artifact mode
9const BC_EXEC_FAILED: i64 = 127
10const BC_CAPTURE_FAILED: i64 = 125
11const BC_EINTR: i64 = 4
12const BC_BOARD_JSON: *u8 = "knowledge/status/sota_board.json"
13const BC_BOARD_LEDGER: *u8 = "knowledge/status/sota_board.ledger"
14
15func bc_prefix_ok(prefix: *u8) -> i64 {
16 let n: i64 = gk_len(prefix)
17 if n <= gk_len("/tmp/" as *u8) { return 0 }
18 if n+gk_len(".missing-argument.json" as *u8)+1 > SYS_PATH_MAX { return 0 }
19 let root: *u8 = "/tmp/" as *u8
20 var i: i64 = 0
21 while i < gk_len(root) { if prefix[i] != root[i] { return 0 } i = i+1 }
22 while i < n {
23 let c: i64 = prefix[i] as i64
24 var ok: i64 = 0
25 if c >= 97 { if c <= 122 { ok = 1 } }
26 if c >= 65 { if c <= 90 { ok = 1 } }
27 if c >= 48 { if c <= 57 { ok = 1 } }
28 if c == 95 { ok = 1 }
29 if c == 45 { ok = 1 }
30 if ok == 0 { return 0 }
31 i = i+1
32 }
33 return 1
34}
35func bc_equal(before: *u8, bn: i64, after: *u8, an: i64) -> i64 {
36 if bn <= 0 { return 0 }
37 if bn != an { return 0 }
38 if (before as i64) <= 0 { return 0 }
39 if (after as i64) <= 0 { return 0 }
40 var i: i64 = 0
41 while i < bn { if before[i] != after[i] { return 0 } i = i+1 }
42 return 1
43}
44func bc_capture(elf: *u8, domain: *u8, out: *u8) -> i64 {
45 let argv: *i64 = sys_mmap(4*8) as *i64
46 let envp: *i64 = sys_mmap(8) as *i64
47 let status: *i64 = sys_mmap(8) as *i64
48 if (argv as i64) <= 0 { return BC_CAPTURE_FAILED }
49 if (envp as i64) <= 0 { return BC_CAPTURE_FAILED }
50 if (status as i64) <= 0 { return BC_CAPTURE_FAILED }
51 let mode: *u8 = "bindings" as *u8
52 argv[0] = elf as i64; argv[1] = mode as i64; argv[2] = domain as i64; argv[3] = 0
53 envp[0] = 0; status[0] = 0
54 let fd: i64 = sys_openat_exclusive(out, BC_FILE_MODE)
55 if fd < 0 { return BC_CAPTURE_FAILED }
56 let pid: i64 = sys_fork()
57 if pid < 0 { sys_close(fd); return BC_CAPTURE_FAILED }
58 if pid == 0 {
59 if fd != 1 { if sys_dup3(fd, 1, 0) < 0 { sys_exit(BC_CAPTURE_FAILED) } }
60 sys_execve_clean(elf, argv, envp)
61 sys_exit(BC_EXEC_FAILED)
62 }
63 var waited: i64 = sys_wait4(pid, status, 0)
64 while waited == 0-BC_EINTR { waited = sys_wait4(pid, status, 0) }
65 let synced: i64 = sys_fsync(fd)
66 sys_close(fd)
67 if waited != pid { return BC_CAPTURE_FAILED }
68 if synced < 0 { return BC_CAPTURE_FAILED }
69 return gk_wait_code(status[0])
70}
71func bc_case(elf: *u8, prefix: *u8, suffix: *u8, domain: *u8, expected_rc: i64, marker: *u8, ctr: *i64) -> i64 {
72 let path: *u8 = sys_mmap(SYS_PATH_MAX)
73 let size: *i64 = sys_mmap(8) as *i64
74 var allocated: i64 = 0
75 if (path as i64) > 0 { if (size as i64) > 0 { allocated = 1 } }
76 gv_check("capture-case-buffers-allocated" as *u8, allocated, ctr)
77 if allocated == 0 { return 0 }
78 let used: i64 = gk_cat(path, 0, prefix)
79 gk_cat(path, used, suffix)
80 let rc: i64 = bc_capture(elf, domain, path)
81 gv_puts("capture_path=" as *u8); gv_puts(path); gv_puts(" exit=" as *u8); gv_num(rc)
82 let output: *u8 = sys_read_file(path, size)
83 gv_puts(" complete_file_bytes=" as *u8); gv_num(size[0]); gv_puts("\n" as *u8)
84 gv_check("staged-owner-exit-matches-contract" as *u8, rc == expected_rc, ctr)
85 var complete: i64 = 0
86 if (output as i64) > 0 { if size[0] > 1 {
87 if output[0] == (123 as u8) { if output[size[0]-1] == (10 as u8) {
88 if output[size[0]-2] == (125 as u8) { complete = gk_has(output, marker) }
89 } }
90 } }
91 gv_check("complete-file-json-envelope-and-case-marker" as *u8, complete, ctr)
92 sys_free_file(output, size[0])
93 return complete
94}
95func main(argc: i64, argv: *i64) -> i64 {
96 if argc != 3 { gv_puts("usage: capture-gate <staged-owner-path> </tmp/unique-basename>\n" as *u8); return 3 }
97 let elf: *u8 = argv[1] as *u8
98 let prefix: *u8 = argv[2] as *u8
99 if bc_prefix_ok(prefix) == 0 { gv_puts("REFUSE temporary basename must remain directly under /tmp\n" as *u8); return 3 }
100 if ep_anchor() < 0 { gv_puts("REFUSE estate anchor unavailable\n" as *u8); return 3 }
101 let ctr: *i64 = gv_ctr()
102 gv_head("Actual staged binding command: complete capture and unchanged board artifacts" as *u8)
103 let jn: *i64 = sys_mmap(8) as *i64
104 let ln: *i64 = sys_mmap(8) as *i64
105 let an: *i64 = sys_mmap(8) as *i64
106 var allocated: i64 = 0
107 if (jn as i64) > 0 { if (ln as i64) > 0 { if (an as i64) > 0 { allocated = 1 } } }
108 gv_check("board-comparison-buffers-allocated" as *u8, allocated, ctr)
109 if allocated == 0 { return gv_verdict("NX-BINDINGS-CAPTURE" as *u8, ctr, "allocation failed before baseline reads" as *u8) }
110 let jb: *u8 = sys_read_file(BC_BOARD_JSON, jn)
111 let lb: *u8 = sys_read_file(BC_BOARD_LEDGER, ln)
112 var ready: i64 = 0
113 if (jb as i64) > 0 { if jn[0] > 0 { if (lb as i64) > 0 { if ln[0] > 0 { ready = 1 } } } }
114 gv_check("existing-board-artifacts-readable-before-command" as *u8, ready, ctr)
115 if ready == 0 { return gv_verdict("NX-BINDINGS-CAPTURE" as *u8, ctr, "no board side-effect claim without baseline bytes" as *u8) }
116 bc_case(elf, prefix, ".charsim.json" as *u8, "charsim" as *u8, 0, "\"domain\":\"charsim\"" as *u8, ctr)
117 bc_case(elf, prefix, ".gameengine.json" as *u8, "gameengine" as *u8, 0, "\"domain\":\"gameengine\"" as *u8, ctr)
118 bc_case(elf, prefix, ".bad-domain.json" as *u8, "../" as *u8, 3, "\"reason\":\"bad_domain\"" as *u8, ctr)
119 bc_case(elf, prefix, ".missing-argument.json" as *u8, 0 as *u8, 3, "usage: nx_sota_status bindings" as *u8, ctr)
120 let ja: *u8 = sys_read_file(BC_BOARD_JSON, an)
121 gv_check("existing-board-json-byte-identical-after-all-cases" as *u8, bc_equal(jb, jn[0], ja, an[0]), ctr)
122 sys_free_file(ja, an[0])
123 let la: *u8 = sys_read_file(BC_BOARD_LEDGER, an)
124 gv_check("existing-board-ledger-byte-identical-after-all-cases" as *u8, bc_equal(lb, ln[0], la, an[0]), ctr)
125 sys_free_file(la, an[0]); sys_free_file(jb, jn[0]); sys_free_file(lb, ln[0])
126 return gv_verdict("NX-BINDINGS-CAPTURE" as *u8, ctr, "complete artifacts retained at printed paths; JSON structure and semantic checker must also pass before promotion" as *u8)
127}