nx_privacy_gate.nx source
↩ module page · 66 lines · 5082 B
1// nx_privacy_gate.nx -- INDEPENDENT GATE: GDPR/CCPA request clocks + breach notification.
2// ZERO storage. The teeth: the 72-hour breach clock runs from AWARENESS (the incident time is not even
3// an input, so it cannot be anchored to by accident); an extension claimed AFTER the original window
4// buys nothing; and encryption excuses telling the DATA SUBJECTS but never the SUPERVISORY AUTHORITY.
5// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
6
7import "nx_privacy_lib.nx"
8import "nx_gate_verdict.nx"
9
10func main(argc: i64, argv: *i64) -> i64 {
11 let ctr: *i64 = gv_ctr()
12 let lbl: *u8 = sys_mmap(32)
13
14 let rx: i64 = 20000
15 let U: i64 = PRV_UNSET
16
17 gv_head("NISHI-PRIVACY-GATE (GDPR/CCPA request clocks + Art 33/34 breach notification)" as *u8)
18
19 // ---- D: subject access request deadlines ----
20 gv_check("D1 GDPR base deadline = 30 days" as *u8, prv_gdpr_dsar_pure(rx, 0, U) == 20030, ctr)
21 gv_check("D2 CCPA base deadline = 45 days" as *u8, prv_ccpa_dsar_pure(rx, 0, U) == 20045, ctr)
22 gv_check("D3 unknown receipt date -> UNKNOWN deadline" as *u8, prv_gdpr_dsar_pure(U, 0, U) == PRV_UNKNOWN, ctr)
23
24 // ---- E: THE EXTENSION RULE -- notice must land inside the original window ----
25 gv_check("E1 GDPR extension noticed on day 10 -> +60 days" as *u8, prv_gdpr_dsar_pure(rx, 1, 20010) == 20090, ctr)
26 gv_check("E2 noticed on the LAST day of the window -> valid" as *u8, prv_gdpr_dsar_pure(rx, 1, 20030) == 20090, ctr)
27 gv_check("E3 noticed ONE DAY LATE -> buys NOTHING, deadline stays 30 days" as *u8, prv_gdpr_dsar_pure(rx, 1, 20031) == 20030, ctr)
28 gv_check("E4 extension claimed but never noticed -> buys nothing" as *u8, prv_gdpr_dsar_pure(rx, 1, U) == 20030, ctr)
29 gv_check("E5 CCPA extension noticed in time -> +45 days" as *u8, prv_ccpa_dsar_pure(rx, 1, 20040) == 20090, ctr)
30 gv_check("E6 CCPA extension noticed late -> stays 45 days" as *u8, prv_ccpa_dsar_pure(rx, 1, 20046) == 20045, ctr)
31
32 // ---- R: response status ----
33 gv_check("R1 responded inside the window -> ON-TIME" as *u8, prv_response_status_pure(20030, 20029) == PRV_ONTIME, ctr)
34 gv_check("R2 responded ON the deadline -> ON-TIME" as *u8, prv_response_status_pure(20030, 20030) == PRV_ONTIME, ctr)
35 gv_check("R3 responded one day after -> LATE" as *u8, prv_response_status_pure(20030, 20031) == PRV_LATE, ctr)
36 gv_check("R4 no response recorded -> UNKNOWN, never on-time by default" as *u8, prv_response_status_pure(20030, U) == PRV_UNKNOWN, ctr)
37 gv_check("R5 days remaining" as *u8, prv_days_remaining_pure(20030, 20020) == 10, ctr)
38 gv_check("R6 days remaining is UNSET when the deadline is unknown" as *u8, prv_days_remaining_pure(PRV_UNKNOWN, 20020) == PRV_UNSET, ctr)
39
40 // ---- B: THE 72-HOUR CLOCK, anchored to AWARENESS ----
41 gv_check("B1 deadline = awareness + 72 hours" as *u8, prv_breach_deadline_pure(1000) == 1072, ctr)
42 gv_check("B2 reported inside 72h -> ON-TIME" as *u8, prv_breach_status_pure(1000, 1050) == PRV_ONTIME, ctr)
43 gv_check("B3 reported exactly at 72h -> ON-TIME" as *u8, prv_breach_status_pure(1000, 1072) == PRV_ONTIME, ctr)
44 gv_check("B4 reported at 73h -> LATE" as *u8, prv_breach_status_pure(1000, 1073) == PRV_LATE, ctr)
45 gv_check("B5 u2605a breach that BEGAN long before is still judged from AWARENESS" as *u8, prv_breach_status_pure(9000, 9050) == PRV_ONTIME, ctr)
46 gv_check("B6 unknown awareness -> UNKNOWN, never assumed compliant" as *u8, prv_breach_status_pure(U, 1050) == PRV_UNKNOWN, ctr)
47 gv_check("B7 never reported -> UNKNOWN, never on-time" as *u8, prv_breach_status_pure(1000, U) == PRV_UNKNOWN, ctr)
48
49 // ---- N: WHO must be told -- Art 33 vs Art 34 ----
50 gv_check("N1 personal data at risk -> tell the AUTHORITY" as *u8, prv_notify_authority_pure(1, 1) == 1, ctr)
51 gv_check("N2 no risk to rights -> no authority notification" as *u8, prv_notify_authority_pure(1, 0) == 0, ctr)
52 gv_check("N3 not personal data -> no notification" as *u8, prv_notify_authority_pure(0, 1) == 0, ctr)
53 gv_check("N4 HIGH risk, unencrypted -> tell the SUBJECTS" as *u8, prv_notify_subjects_pure(1, 1, 0) == 1, ctr)
54 gv_check("N5 u2605encrypted -> subjects need NOT be told" as *u8, prv_notify_subjects_pure(1, 1, 1) == 0, ctr)
55 gv_check("N6 u2605u2605but the AUTHORITY must STILL be told even when encrypted" as *u8, prv_notify_authority_pure(1, 1) == 1, ctr)
56 gv_check("N7 merely 'a risk' is not HIGH risk -> subjects not told" as *u8, prv_notify_subjects_pure(1, 0, 0) == 0, ctr)
57
58 // ---- L: labels and exposure ----
59 prv_status_label(PRV_LATE, lbl)
60 gv_check("L1 late label" as *u8, mt_streq(lbl, "LATE" as *u8) == 1, ctr)
61 prv_status_label(PRV_UNKNOWN, lbl)
62 gv_check("L2 unknown label" as *u8, mt_streq(lbl, "UNKNOWN" as *u8) == 1, ctr)
63 gv_check("L3 exposure sums late responses, late breaches and unknowns" as *u8, prv_exposure_pure(2, 1, 4) == 7, ctr)
64
65 return gv_verdict("PRIVACY-GDPR" as *u8, ctr, "72h runs from AWARENESS; a late extension buys nothing; encryption excuses subjects not regulators" as *u8)
66}