code wiki / _hdl_build / nx_pkg.nx

nx_pkg.nx

buildroot/runtime/_hdl_build/nx_pkg.nx

38041 B740 linesdepth 5pulls 8 transitivereach 0 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_pkg.nx -- THE SOVEREIGN CONTENT-ADDRESSED PACKAGE LANE (LR3 of /compare/lang), carrying the original dependency-resolution self-test it grew from (verb `selftest`, still the NO-ARG DEFAULT so no existing caller loses behaviour). WHY THIS EXISTS. The 2025 registry worms self-replicated across 500+ npm packages by exploiting exactly two assumptions: install-time code execution, and blind trust that a NAME resolves to whatever `latest` happens to be. Go answered with a module proxy, a signed transparency log (sumdb), and no install scripts. This lane does not GUARD that attack surface, it REMOVES it: THE IDENTITY OF A MODULE IS THE HASH OF ITS BYTES. There is no version negotiation, so there is no `latest` to poison. The resolve primitive takes a digest, not a name, so there is nothing to squat. And resolution never interprets, forks or executes one byte of module content -- it reads, verifies, and writes. THE ONE LAW: THE STORE PATH IS A HINT, THE HASH IS THE IDENTITY. A blob at <store>/<digest> is RE-HASHED on every resolve and REFUSED if it does not hash to the digest that was asked for. An attacker who can write the store cannot make it serve different bytes; the most they achieve is a named, loud refusal. EXTENDS THE ESTATE'S EXISTING CONTENT-ADDRESSING, DOES NOT ADD A SECOND ONE: sha256_digest (nx_sha256.nx) -- the same digest nx_filehash / nx_closurehash / nx_content_put use sys_read_file (nx_syscalls.nx) -- sizes its buffer from the file, so a module CANNOT short-read lcf_* (nx_lineconf_lib.nx) -- line-anchored conf, LCF_MISS -> REFUSE, never a silent default There is no new hash, no new store format, no second ruler. VERBS (every path and policy value comes from a conf file; an absent key REFUSES, it never defaults): nx_pkg cas_put <file> [conf] -> address a file by content; prints its digest nx_pkg cas_resolve <digest64> <dest> [conf] -> THE CONTRACT PRIMITIVE (pkg_cas_resolve) nx_pkg pin <name> <digest64> [conf] -> bind a logical name to a digest (THE TRUST BOUNDARY) nx_pkg resolve <name> <dest> [conf] -> exact-match pinned name -> digest -> cas_resolve nx_pkg logverify [conf] -> walk the hash-chained transparency journal nx_pkg selftest -> the original dep-resolution teeth (T1..T4) An UNRECOGNISED verb prints usage and exits 3. It never falls through to a permissive default -- the route-mode defect (an unknown token silently selecting the permissive branch) is live in this estate today and this is the one place it must not be repeated. WHAT THE TRANSPARENCY JOURNAL PROVES, STATED HONESTLY. Every put/resolve appends <seq>|<op>|<digest>|<bytes>|<prev_chain>|<chain> with chain = sha256(prev|digest|bytes) so a retroactive edit to any past row breaks every chain link after it, and an append REFUSES on a broken chain rather than extending it. That is TAMPER-EVIDENCE against an editor who does not rewrite the whole file. It is NOT Go's sumdb: there is one writer, no signature, no gossiped tree head and no inclusion proofs, so an attacker holding write access to the entire journal can recompute it from

dependencies 5 imports · 0 importers

nx_syscalls.nx nx_itoa_lib.nx nx_g_puts_lib.nx nx_sha256.nx nx_lineconf_lib.nx nx_pkg.nx

imports: nx_syscalls.nxnx_itoa_lib.nxnx_g_puts_lib.nxnx_sha256.nxnx_lineconf_lib.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main pk_selftest g_puts sys_write sys_mmap nxa_die sys_write ↻ sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ psum pkg_needed pkg_topo sys_mmap ↻ ck g_puts ↻ pkg_verify psum ↻ pk_sha_hex sys_mmap ↻ sha256_digest sys_mmap ↻ sha256_init sys_mmap ↻ sha256_seed_allocated sha256_k sha256_update sha256_compress_ni_blocks blk_set_byte sha256_compress sha256_compress_ni

structs

435struct PkConf { store: *u8, lock: *u8, log: *u8, ok: i64 }

consts

66const PK_DIGEST_BYTES: i64 = 32 // SHA-256 output width, fixed by the algorithm
67const PK_SHAHEX: i64 = 64 // = PK_DIGEST_BYTES * 2, asserted at runtime below
68const PK_I64_DIGITS: i64 = 20 // widest decimal i64 incl sign, fixed by the type
69const PK_BAR: i64 = 124 // '|' field separator
70const PK_NL: i64 = 10
71const PK_SLASH: i64 = 47
72const PK_DOT: i64 = 46
73const PK_ASCII_0: i64 = 48
74const PK_ASCII_9: i64 = 57
75const PK_ASCII_a: i64 = 97
76const PK_ASCII_f: i64 = 102
77const PK_FD_OUT: i64 = 1
78const PK_FD_ERR: i64 = 2
79const PK_NFIELDS: i64 = 6
80const PK_F_SEQ: i64 = 0
81const PK_F_OP: i64 = 1
82const PK_F_DIG: i64 = 2
83const PK_F_BYTES: i64 = 3
84const PK_F_PREV: i64 = 4
85const PK_F_CHAIN: i64 = 5
86const PK_CONF_DEFAULT: *u8 = "knowledge/pkg_cas.conf" as *u8
90const PK_OK: i64 = 0
91const PK_R_MALFORMED: i64 = 1
92const PK_R_ABSENT: i64 = 2
93const PK_R_MISMATCH: i64 = 3
94const PK_R_DEST: i64 = 4
95const PK_R_IO: i64 = 5
96const PK_R_CHAIN: i64 = 6
97const PK_R_NOTPINNED: i64 = 7
98const PK_R_PINCONFLICT: i64 = 8
99const PK_R_PINAMBIG: i64 = 9
100const PK_R_CONF: i64 = 10
102const PK_EXIT_USAGE: i64 = 3
103const PK_EXIT_CONF: i64 = 4
104const PK_EXIT_MALFORMED: i64 = 5
105const PK_EXIT_ABSENT: i64 = 6
106const PK_EXIT_MISMATCH: i64 = 7
107const PK_EXIT_DEST: i64 = 8
108const PK_EXIT_NOTPINNED: i64 = 9
109const PK_EXIT_PINCONFLICT: i64 = 10
110const PK_EXIT_CHAIN: i64 = 11
111const PK_EXIT_IO: i64 = 12
112const PK_EXIT_PINAMBIG: i64 = 13
461const MAXD: i64 = 4

functions

114func pk_rule(code: i64) -> *u8
called by 2: pk_refusemain
127func pk_exit_for(code: i64) -> i64
called by 2: pk_refusemain
143func pk_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
144func pk_eputs(s: *u8) -> i64 { sys_write(PK_FD_ERR, s, pk_slen(s)); return 0 }
called by 2: pk_usagemain calls 2: sys_writepk_slen
145func pk_num(v: i64) -> i64 { nxi_out(v); return 0 }
called by 1: main calls 1: nxi_out
146func pk_cat(d: *u8, o: i64, s: *u8) -> i64 { var p: i64 = o; var i: i64 = 0; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } d[p] = 0 as u8; return p }
147func pk_streq(a: *u8, b: *u8) -> i64
153func pk_starts(p: *u8, pre: *u8) -> i64 { var i: i64 = 0; while pre[i] != (0 as u8) { if p[i] != pre[i] { return 0 } i = i + 1 } return 1 }
called by 1: pk_dest_ok
154func pk_dotdot(p: *u8) -> i64 { var i: i64 = 0; while p[i] != (0 as u8) { if (p[i] as i64) == PK_DOT { if (p[i+1] as i64) == PK_DOT { return 1 } } i = i + 1 } return 0 }
called by 1: pk_dest_ok
155func pk_atoi(s: *u8) -> i64
called by 1: pk_log_verify
170func pk_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
called by 1: main calls 2: sys_openat_rdsys_close
173func pk_mkdir(path: *u8) -> i64
called by 1: main calls 2: sys_mmapsys_munmap
180func pk_hex_into(dig: *u8, out: *u8) -> i64
called by 1: pk_sha_hex
192func pk_sha_hex(buf: *u8, n: i64, outhex: *u8) -> i64
201func pk_is_hex64(s: *u8) -> i64
215func pk_dest_ok(p: *u8) -> i64
called by 1: pkg_cas_resolve calls 2: pk_dotdotpk_starts
224func pk_blob_path(store: *u8, dighex: *u8) -> *u8
232func pk_write_atomic(finalpath: *u8, buf: *u8, n: i64) -> i64
253func pk_genesis(out: *u8) -> i64 { var i: i64 = 0; while i < PK_SHAHEX { out[i] = PK_ASCII_0 as u8; i = i + 1 } out[PK_SHAHEX] = 0 as u8; return PK_SHAHEX }
called by 1: pk_log_verify
255func pk_chain_step(prevhex: *u8, dighex: *u8, nbytes: i64, outhex: *u8) -> i64
268func pk_field(buf: *u8, st: i64, ln: i64, idx: i64, out: *u8, cap: i64) -> i64
called by 1: pk_log_verify
288func pk_log_verify(logpath: *u8, entries: *i64, head: *u8) -> i64
339func pk_log_append(logpath: *u8, op: *u8, dighex: *u8, nbytes: i64) -> i64
381func pkg_cas_resolve(store: *u8, dighex: *u8, dest: *u8, outbytes: *i64) -> i64
405func pk_lock_lookup(buf: *u8, n: i64, name: *u8, outdig: *u8) -> i64
called by 1: main calls 1: pk_slen
436func pk_conf_load(confpath: *u8) -> *PkConf
called by 1: main calls 3: sys_mmapsys_read_filelcf_str
456func g_pn(v: i64) -> i64 { nxi_out(v); return 0 }
called by 1: pk_selftest calls 1: nxi_out
457func ck(name: *u8, c: i64) -> i64 { if c==1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) } g_puts(name); g_puts("\n" as *u8); return c }
called by 1: pk_selftest calls 1: g_puts
458func slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
459func psum(s: *u8) -> i64 { var acc: i64=0; var i: i64=0; while s[i]!=(0 as u8){ acc=acc+(s[i] as i64); i=i+1 } return acc }
463func pkg_needed(target: i64, ndep: *i64, dep: *i64, N: i64, needed: *i64) -> i64
called by 1: pk_selftest
469func pkg_topo(ndep: *i64, dep: *i64, N: i64, order: *i64) -> i64
called by 1: pk_selftest calls 1: sys_mmap
480func pkg_verify(content: *u8, expected: i64) -> i64 { if psum(content)==expected { return 1 } return 0 }
called by 1: pk_selftest calls 1: psum
482func pk_selftest() -> i64
536func pk_usage() -> i64
called by 1: main calls 1: pk_eputs
553func pk_refuse(prefix: *u8, code: i64) -> i64
called by 1: main calls 3: g_putspk_rulepk_exit_for
558func main(argc: i64, argv: *i64) -> i64