nx_license_check.nx source
↩ module page · 223 lines · 9037 B
1// nx_license_check.nx -- Layer-3 lexical grader perspective.
2//
3// Enforces the LICENSING WALL per refined cardinal
4// feedback-licensing-absorb-vs-copy-discipline (2026-05-15):
5//
6// "i dont want direct copies in the code that can be suable or allow
7// loss of sovereignty i want the papers in the library but we need
8// a wall that we arent copying from them something that needs
9// attribution or licensing"
10//
11// Scans a substrate source file for the
12//
13// // license_tier: <TIER>
14//
15// header line. Only THREE tier values are permitted in substrate
16// code:
17//
18// TIER_0_UNENCUMBERED -- public-domain / CC0 / U.S. Govt work;
19// verbatim safe
20// INDEPENDENT_REDERIVE -- built from published spec, no source copy
21// ORIGINAL -- substrate-original, no external ancestor
22//
23// Anything else (or no header at all) is a LOSE. The grader emits a
24// named_improvement string telling the maintainer exactly how to
25// remedy the file.
26//
27// Substrate-original code, written from scratch in this file.
28//
29// license_tier: ORIGINAL
30//
31// nx_safety_envelope: (schema: nishi-library/seeds/safety-critical-standards.toml)
32// intended_use: "Layer-3 license-tier grader -- enforces the
33// TIER_0_UNENCUMBERED / INDEPENDENT_REDERIVE /
34// ORIGINAL wall across substrate. Refuses
35// sneaking in AGPL / GPL / MIT / Apache / OSI
36// annotations. Cardinal feedback-no-standard-
37// OSI-license-custom-tbd enforcement point."
38// sil_target: SIL2 (licensing wall breach = sovereignty
39// loss + suability risk; cardinal-
40// critical)
41// asil_target: QM
42// dal_target: NONE
43// iec_62304_class: NONE
44// evidence: [no_floating_point, sealed_verdict_enum,
45// per_tier_token_table_complete,
46// feedback-no-standard-OSI-license-custom-tbd_enforcement,
47// feedback-nishi-library-open-research-not-paywall-funding_companion]
48// hazard_register: [bug-tape-MIT-License-snuck-in-via-paste,
49// bug-tape-AGPL-header-from-pre-existing-c-file,
50// bug-tape-license-tier-missing-on-new-substrate-file]
51// residual_risk: "Detects ONLY the canonical license-text
52// signatures. Obfuscated copies (e.g.
53// paraphrased AGPL clauses) bypass detection.
54// Defense-in-depth: license_tier header
55// declaration is a SECONDARY axis; both signals
56// must agree for PASS."
57// verdict: NOT_YET_EVALUATED
58
59import "nx_syscalls.nx"
60import "nx_runtime.nx"
61import "nx_types.nx"
62import "nx_tier.nx"
63
64// ---- Sealed enum: license tier --------------------------------------
65
66// header not found
67const NX_LIC_UNKNOWN: nx_int = 0
68// OK tiers (allowed in substrate code)
69const NX_LIC_TIER_0_UNENCUMBERED: nx_int = 1
70const NX_LIC_INDEPENDENT_REDERIVE: nx_int = 2
71const NX_LIC_ORIGINAL: nx_int = 3
72// header present but tier is one of the banned values
73const NX_LIC_FORBIDDEN: nx_int = 4
74// arity guard
75const NX_LIC_N: nx_int = 5
76
77func nx_license_tier_is_valid(t: nx_int) -> nx_int {
78 if t < 0 { return 0 }
79 if t >= NX_LIC_N { return 0 }
80 return 1
81}
82
83// ---- Sealed enum: license verdict -----------------------------------
84//
85// Maps each tier to one of the 4 graded-card verdict values used by
86// nx_quality_grade. Mirrors NX_QV_WIN / NX_QV_LOSE / NX_QV_TIE
87// without importing the grader module (this is a Layer-3 perspective
88// that runs standalone too).
89
90const NX_LIC_VERDICT_WIN: nx_int = 1
91const NX_LIC_VERDICT_LOSE: nx_int = 2
92const NX_LIC_VERDICT_TIE: nx_int = 3
93const NX_LIC_VERDICT_UNMEASURED: nx_int = 0
94
95func nx_license_verdict_for_tier(t: nx_int) -> nx_int {
96 if t == NX_LIC_TIER_0_UNENCUMBERED { return NX_LIC_VERDICT_WIN }
97 if t == NX_LIC_INDEPENDENT_REDERIVE { return NX_LIC_VERDICT_WIN }
98 if t == NX_LIC_ORIGINAL { return NX_LIC_VERDICT_WIN }
99 if t == NX_LIC_FORBIDDEN { return NX_LIC_VERDICT_LOSE }
100 if t == NX_LIC_UNKNOWN { return NX_LIC_VERDICT_LOSE }
101 return NX_LIC_VERDICT_UNMEASURED
102}
103
104// ---- Byte helpers ---------------------------------------------------
105
106func _starts_with(src: *u8, src_len: nx_int, off: nx_int, needle: *u8, needle_len: nx_int) -> nx_int {
107 var k: nx_int = 0
108 if off < 0 { return 0 }
109 if off + needle_len > src_len { return 0 }
110 let base: *u8 = (src as nx_int + off) as *u8
111 while k < needle_len {
112 let a: nx_int = base[k] as nx_int
113 let b: nx_int = needle[k] as nx_int
114 if (a & 255) != (b & 255) { return 0 }
115 k = k + 1
116 }
117 return 1
118}
119
120func _skip_spaces(src: *u8, src_len: nx_int, off: nx_int) -> nx_int {
121 var i: nx_int = off
122 while i < src_len {
123 let p: *u8 = (src as nx_int + i) as *u8
124 let c: nx_int = p[0] as nx_int
125 if (c & 255) != 32 { return i }
126 i = i + 1
127 }
128 return i
129}
130
131// ---- Tier match -----------------------------------------------------
132//
133// Given a source position pointing at the start of a tier name (after
134// `// license_tier:` and any leading spaces), match against the
135// allowed + forbidden sets. Forbidden = any tier name that isn't one
136// of the three OK values; we treat them all the same way because the
137// grader's job is to enforce the wall, not classify the violation.
138
139func _match_tier_at(src: *u8, src_len: nx_int, off: nx_int) -> nx_int {
140 let t0: *u8 = "TIER_0_UNENCUMBERED" as *u8
141 if _starts_with(src, src_len, off, t0, 19) == 1 {
142 return NX_LIC_TIER_0_UNENCUMBERED
143 }
144 let ir: *u8 = "INDEPENDENT_REDERIVE" as *u8
145 if _starts_with(src, src_len, off, ir, 20) == 1 {
146 return NX_LIC_INDEPENDENT_REDERIVE
147 }
148 let og: *u8 = "ORIGINAL" as *u8
149 if _starts_with(src, src_len, off, og, 8) == 1 {
150 return NX_LIC_ORIGINAL
151 }
152 // Any other identifier after the header tag counts as a forbidden
153 // tier. This catches typos AND deliberate banned values like
154 // COPY_WITH_ATTRIB, INTENT_ONLY, REDERIVED (older drafts).
155 return NX_LIC_FORBIDDEN
156}
157
158// ---- Public entry: scan source for the license_tier header ---------
159
160func nx_license_extract(src: *u8, src_len: nx_int) -> nx_int {
161 var i: nx_int = 0
162 if src_len <= 0 { return NX_LIC_UNKNOWN }
163 let tag: *u8 = "// license_tier:" as *u8
164 let tag_len: nx_int = 16
165 let cap: nx_int = src_len - tag_len
166 while i < cap {
167 let line_start: nx_int = 0
168 if i == 0 {
169 if _starts_with(src, src_len, i, tag, tag_len) == 1 {
170 let after: nx_int = _skip_spaces(src, src_len, i + tag_len)
171 return _match_tier_at(src, src_len, after)
172 }
173 } else {
174 let prev: *u8 = (src as nx_int + i - 1) as *u8
175 let pc: nx_int = prev[0] as nx_int
176 if (pc & 255) == 10 {
177 if _starts_with(src, src_len, i, tag, tag_len) == 1 {
178 let after: nx_int = _skip_spaces(src, src_len, i + tag_len)
179 return _match_tier_at(src, src_len, after)
180 }
181 }
182 }
183 i = i + 1
184 }
185 return NX_LIC_UNKNOWN
186}
187
188// ---- Named improvement string ---------------------------------------
189
190func nx_license_named_improvement(t: nx_int) -> *u8 {
191 if t == NX_LIC_UNKNOWN {
192 return "add `// license_tier: ORIGINAL` (or TIER_0_UNENCUMBERED / INDEPENDENT_REDERIVE) to the file header" as *u8
193 }
194 if t == NX_LIC_FORBIDDEN {
195 return "license_tier is not one of TIER_0_UNENCUMBERED / INDEPENDENT_REDERIVE / ORIGINAL -- reroute through nishi-library research catalog and rederive" as *u8
196 }
197 return "" as *u8
198}
199
200// ---- Tier name reflection (for human-readable emit) -----------------
201
202func nx_license_tier_name(t: nx_int) -> *u8 {
203 if t == NX_LIC_TIER_0_UNENCUMBERED { return "TIER_0_UNENCUMBERED" as *u8 }
204 if t == NX_LIC_INDEPENDENT_REDERIVE { return "INDEPENDENT_REDERIVE" as *u8 }
205 if t == NX_LIC_ORIGINAL { return "ORIGINAL" as *u8 }
206 if t == NX_LIC_FORBIDDEN { return "FORBIDDEN" as *u8 }
207 if t == NX_LIC_UNKNOWN { return "UNKNOWN" as *u8 }
208 return "INVALID" as *u8
209}
210
211// ---- File-level helper: read + extract in one call ------------------
212//
213// Returns the tier code; on read failure returns NX_LIC_UNKNOWN (which
214// is itself a LOSE -- a file we can't read is a file we can't audit).
215
216func nx_license_scan_file(path: *u8) -> nx_int {
217 let len_raw: *u8 = sys_mmap(16)
218 let len_p: *i64 = len_raw as *i64
219 let src: *u8 = sys_read_file(path, len_p)
220 if src == (0 as *u8) { return NX_LIC_UNKNOWN }
221 let src_len: nx_int = len_p[0]
222 return nx_license_extract(src, src_len)
223}