code wiki / _hdl_build / nx_nvd_ingest.nx

nx_nvd_ingest.nx source

↩ module page · 175 lines · 7893 B

1// nx_nvd_ingest.nx -- NAS-side API-WRAP ingester for NIST's National Vulnerability Database (NVD REST 2.0). 2// A DIFFERENT asset TYPE from the DCAT catalog pager (nx_nist_ingest): a JSON REST API with nested fields, 3// not HTML/DCAT. Proves the pipeline is NOT overfit to one shape. Fetches 4// services.nvd.nist.gov/rest/json/cves/2.0, splits vulnerabilities[] on {"cve":{"id":", prepends a 5// CVE-id/severity/description title, and dp_ingest's each into the domain's PUBLIC corpus so the CVE id, 6// CVSS severity, description, CPE and references are all BM25-searchable. BOUNDED + HONEST: logs 7// totalResults available vs the slice ingested (no silent truncation). Reuses nx_fetch_any (S1/S2) + 8// dp_ingest. Runs in nishihost CWD (trust store + seg store resolve). Anti-overfit: same fetch+ingest 9// spine, type-appropriate parse -- exactly the ontology pipeline's per-type extractor. 10// usage: nx_nvd_ingest <domain> <count> [startIndex] e.g. nx_nvd_ingest nishifamily.com 500 0 11// license_tier: ORIGINAL | genealogy_id: nishi_nvd_ingest_2026_07_14 12import "nx_syscalls.nx" 13import "nx_x509_trust_store.nx" 14import "nx_trust_store_load_from_certdata.nx" 15import "nx_https_fetch_follow.nx" 16import "nx_fetch_any.nx" 17import "nx_docportal_lib.nx" 18const K_MAGIC_2000: i64 = 2000 19const K_MAGIC_4194304: i64 = 4194304 20const K_MAGIC_16777216: i64 = 16777216 21const K_MAGIC_8192: i64 = 8192 22const K_MAGIC_786432: i64 = 786432 23 24func nv_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 25func nv_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 26func nv_putn(v: i64) -> i64 { 27 let t: *u8 = sys_mmap(32) 28 var m: i64 = v 29 var k: i64 = 0 30 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 31 if m == 0 { t[0] = 48 as u8; k = 1 } 32 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 33 let b: *u8 = sys_mmap(32) 34 var i: i64 = 0 35 while i < k { b[i] = t[k - 1 - i]; i = i + 1 } 36 sys_write(1, b, k) 37 return 0 38} 39func nv_find(hay: *u8, hl: i64, start: i64, needle: *u8, nl: i64) -> i64 { 40 var i: i64 = start 41 while i + nl <= hl { 42 var j: i64 = 0 43 while j < nl { if hay[i + j] != needle[j] { j = nl + 1 } else { j = j + 1 } } 44 if j == nl { return i } 45 i = i + 1 46 } 47 return 0 - 1 48} 49func nv_atoi(s: *u8) -> i64 { 50 var v: i64 = 0 51 var i: i64 = 0 52 var go: i64 = 1 53 while go == 1 { 54 let c: i64 = s[i] as i64 55 if c < 48 { go = 0 } else { if c > 57 { go = 0 } else { v = v * 10 + (c - 48); i = i + 1 } } 56 } 57 return v 58} 59// read a base-10 integer out of buf starting at pos (skips nothing; stops at first non-digit). 60func nv_readint(buf: *u8, hl: i64, pos: i64) -> i64 { 61 var v: i64 = 0 62 var i: i64 = pos 63 var go: i64 = 1 64 while go == 1 { 65 if i >= hl { go = 0 } else { 66 let c: i64 = buf[i] as i64 67 if c < 48 { go = 0 } else { if c > 57 { go = 0 } else { v = v * 10 + (c - 48); i = i + 1 } } 68 } 69 } 70 return v 71} 72func nv_scat(buf: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { buf[o + i] = s[i]; i = i + 1 } return o + i } 73func nv_ncat(buf: *u8, o: i64, v: i64) -> i64 { 74 let t: *u8 = sys_mmap(32); var m: i64 = v; var k: i64 = 0 75 if m == 0 { t[0] = 48 as u8; k = 1 } 76 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 77 var i: i64 = 0 78 while i < k { buf[o + i] = t[k - 1 - i]; i = i + 1 } 79 return o + k 80} 81// copy src[from..to) into doc[dl..], bounded by doccap; return new dl. 82func nv_copy(doc: *u8, dl: i64, doccap: i64, src: *u8, from: i64, to: i64) -> i64 { 83 var i: i64 = from 84 var d: i64 = dl 85 while i < to { if d >= doccap - 1 { return d } doc[d] = src[i]; d = d + 1; i = i + 1 } 86 return d 87} 88// find `key` in src[start..limit), then copy its quoted value (up to the next ") into doc[dl..]; return new dl. 89func nv_field(doc: *u8, dl: i64, doccap: i64, src: *u8, start: i64, limit: i64, key: *u8, keylen: i64) -> i64 { 90 let p: i64 = nv_find(src, limit, start, key, keylen) 91 if p < 0 { return dl } 92 var i: i64 = p + keylen 93 var d: i64 = dl 94 var go: i64 = 1 95 while go == 1 { 96 if i >= limit { go = 0 } else { 97 if src[i] == (34 as u8) { go = 0 } else { if d < doccap - 1 { doc[d] = src[i]; d = d + 1 } i = i + 1 } 98 } 99 } 100 return d 101} 102 103func nv_ingest_record(domain: *u8, out: *u8, recstart: i64, recend: i64, doc: *u8, doccap: i64, cidp: *i64) -> i64 { 104 var dl: i64 = 0 105 dl = nv_field(doc, dl, doccap, out, recstart, recend, "\"id\":\"" as *u8, 6) // CVE-YYYY-NNNNN 106 dl = nv_scat(doc, dl, " [severity " as *u8) 107 dl = nv_field(doc, dl, doccap, out, recstart, recend, "\"baseSeverity\":\"" as *u8, 16) 108 dl = nv_scat(doc, dl, "] " as *u8) 109 dl = nv_field(doc, dl, doccap, out, recstart, recend, "\"value\":\"" as *u8, 9) // first (en) description 110 doc[dl] = 10 as u8; dl = dl + 1 111 dl = nv_scat(doc, dl, "NIST National Vulnerability Database (NVD) -- services.nvd.nist.gov (CVE / CVSS / CPE).\n" as *u8) 112 dl = nv_copy(doc, dl, doccap, out, recstart, recend) // raw record JSON (bounded) 113 if dl <= 0 { return 0 } 114 dp_ingest(domain, DP_VIS_PUBLIC, doc, dl, cidp) 115 return 1 116} 117 118func main(argc: i64, argv: *i64) -> i64 { 119 if argc < 3 { nv_puts("usage: nx_nvd_ingest <domain> <count> [startIndex]\n" as *u8); return 2 } 120 let domain: *u8 = argv[1] as *u8 121 var count: i64 = nv_atoi(argv[2] as *u8) 122 if count > K_MAGIC_2000 { count = K_MAGIC_2000 } 123 if count < 1 { count = 1 } 124 var start: i64 = 0 125 if argc > 3 { start = nv_atoi(argv[3] as *u8) } 126 127 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, K_MAGIC_4194304) 128 if r <= 0 { nv_puts("STORE-FAIL: data/mozilla_certdata.txt\n" as *u8); return 1 } 129 let store: *TrustStore = r as *TrustStore 130 131 let cap: i64 = K_MAGIC_16777216 132 let out: *u8 = sys_mmap(cap) 133 let att: *u8 = sys_mmap(K_MAGIC_8192) 134 let status: *i64 = sys_mmap(16) as *i64 135 let empty: *u8 = sys_mmap(8); empty[0] = 0 as u8 136 let urlbuf: *u8 = sys_mmap(512) 137 let doccap: i64 = K_MAGIC_786432 138 let doc: *u8 = sys_mmap(doccap) 139 let cidp: *i64 = sys_mmap(16) as *i64 140 141 var o: i64 = 0 142 o = nv_scat(urlbuf, o, "https://services.nvd.nist.gov/rest/json/cves/2.0?resultsPerPage=" as *u8) 143 o = nv_ncat(urlbuf, o, count) 144 o = nv_scat(urlbuf, o, "&startIndex=" as *u8) 145 o = nv_ncat(urlbuf, o, start) 146 urlbuf[o] = 0 as u8 147 148 status[0] = 0 149 let n: i64 = nx_fetch_any(urlbuf, store, out, cap, 6, status, empty, 0, att, K_MAGIC_8192) 150 if n <= 0 { nv_puts("FETCH-FAIL (see cascade attempts):\n" as *u8); nv_puts(att); return 1 } 151 152 var total: i64 = 0 153 let trp: i64 = nv_find(out, n, 0, "\"totalResults\":" as *u8, 15) 154 if trp >= 0 { total = nv_readint(out, n, trp + 15) } 155 156 let rd: i64 = nv_find(out, n, 0, "\"vulnerabilities\"" as *u8, 17) 157 var ing: i64 = 0 158 if rd >= 0 { 159 var recstart: i64 = nv_find(out, n, rd, "{\"cve\":{\"id\":\"" as *u8, 14) 160 while recstart >= 0 { 161 let nextrec: i64 = nv_find(out, n, recstart + 14, "{\"cve\":{\"id\":\"" as *u8, 14) 162 var recend: i64 = nextrec 163 if recend < 0 { recend = n } 164 ing = ing + nv_ingest_record(domain, out, recstart, recend, doc, doccap, cidp) 165 recstart = nextrec 166 } 167 } else { nv_puts("NO-vulnerabilities-array (status=" as *u8); nv_putn(status[0]); nv_puts(")\n" as *u8) } 168 169 nv_puts("NVD-INGEST totalResults=" as *u8); nv_putn(total) 170 nv_puts(" startIndex=" as *u8); nv_putn(start) 171 nv_puts(" requested=" as *u8); nv_putn(count) 172 nv_puts(" ingested=" as *u8); nv_putn(ing) 173 nv_puts(" (bounded slice; remaining not silently dropped: totalResults-ingested still available via startIndex paging)\n" as *u8) 174 return 0 175}