code wiki / (root) / nx_asset_access.nx

nx_asset_access.nx source

↩ module page · 70 lines · 3936 B

1// nx_asset_access.nx -- UNIVERSAL ORGANIZATION TOOLING arc, R6: ACCESS CLASSIFY (the asset PDP). 2// 3// The operator's professional+private split + the image-stack "operator-only" law (search-by-image 4// is operator-only, deny-by-default, fail-closed): an asset is RELEASED to a requester ONLY IF the 5// requester's clearance level >= the level the record's `classification` field demands. Anything 6// else -- a missing classification, an unrecognized classification, or insufficient clearance -- is a 7// DENY. DENY-BY-DEFAULT + FAIL-CLOSED (Rule 12), exactly like nx_access_wall's PDP, but FOCUSED on 8// the one signal an asset record already carries (org_research.tsv private-vs-pro-acl). 9// 10// ZERO new auth/crypto -- pure COMPOSITION (Rule 15): it DECODES the unified content-addressed record 11// via nx_asset_record (ar_decode / ar_get) and gates on its own classification field. The classification 12// travels INSIDE the canonical record bytes, so it is bound to the record's CID (change the class -> a 13// different CID): the access policy cannot be silently separated from the asset. This verdict is exactly 14// the L2/L5 identity-policy decision a daemon would feed into nx_access_wall's aw_decide (this organ is 15// the asset-aware policy; aw_decide stays the network/device/rate composition point). 16// 17// No hardware/persistent-firmware writes (Rule 26). license_tier: ORIGINAL 18import "nx_syscalls.nx" 19import "nx_uxf_decode.nx" 20import "nx_asset_record.nx" 21 22// clearance levels (data-driven, named -- law #11; higher = more access). 23func AA_ANON() -> i64 { return 0 } // public internet / unauthenticated 24func AA_FAMILY() -> i64 { return 1 } // a family member 25func AA_PRO() -> i64 { return 2 } // professional / staff 26func AA_OWNER() -> i64 { return 3 } // the operator (lvl-3) 27 28// decision codes (negative = deny; the SPECIFIC reason so an audit point can log WHY). 29const AA_ALLOW: i64 = 1 30const AA_DENY_CLEARANCE: i64 = 0 - 1 // requester level below the record's required level 31const AA_DENY_UNKNOWN: i64 = 0 - 2 // classification missing / unrecognized -> fail-closed 32 33func aa_streq(a: *u8, b: *u8) -> i64 { 34 var i: i64 = 0 35 while 1 == 1 { 36 if a[i] != b[i] { return 0 } 37 if a[i] == (0 as u8) { return 1 } 38 i = i + 1 39 } 40 return 1 41} 42 43// required clearance level for a classification string. Unrecognized / null -> -1 (fail-closed). 44// "public" is the ONLY class an anon requester may read; everything sensitive needs real clearance. 45func aa_required_level(classification: *u8) -> i64 { 46 if (classification as i64) == 0 { return 0 - 1 } 47 if aa_streq(classification, "public\x00" as *u8) == 1 { return AA_ANON() } 48 if aa_streq(classification, "professional\x00" as *u8) == 1 { return AA_PRO() } 49 if aa_streq(classification, "private\x00" as *u8) == 1 { return AA_OWNER() } 50 if aa_streq(classification, "operator-only\x00" as *u8) == 1 { return AA_OWNER() } 51 return 0 - 1 52} 53 54// THE DECISION over a record's canonical bytes. Decode -> read the classification field -> compare to 55// the requester's clearance. Returns AA_ALLOW / AA_DENY_*. DENY-BY-DEFAULT: every path that is not a 56// full ALLOW is a DENY. A malformed record (canon_decode < 0) or a missing/unknown class fails CLOSED. 57func aa_decide(record_bytes: *u8, n: i64, requester_level: i64) -> i64 { 58 let dk: *i64 = sys_mmap(8 * 32) as *i64 59 let dv: *i64 = sys_mmap(8 * 32) as *i64 60 let nf: i64 = canon_decode(record_bytes, n, dk, dv, 32) 61 if nf < 0 { return AA_DENY_UNKNOWN } 62 let cls: *u8 = ar_get(dk, dv, nf, "classification\x00" as *u8) 63 let req: i64 = aa_required_level(cls) 64 if req < 0 { return AA_DENY_UNKNOWN } 65 if requester_level >= req { return AA_ALLOW } 66 return AA_DENY_CLEARANCE 67} 68 69// boolean convenience for an enforcement point: 1 = released, 0 = withheld. 70func aa_allowed(verdict: i64) -> i64 { if verdict == AA_ALLOW { return 1 } return 0 }