mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-17 23:09:35 +00:00
- Add public_launch ACA package (gate, pilot_tracker, pdpl, brand_moat) - Register GET/POST /api/v1/public-launch/* router in api/main - Add 18 unit tests, MASTER_STRATEGIC_PLAN, PUBLIC_LAUNCH_READINESS - Refresh POST_MERGE_VERIFICATION snapshot; vendor patch for git apply Verified: 797 passed (6 skipped), ROUTE_CHECK_OK, SMOKE_INPROCESS_OK
177 lines
5.9 KiB
Python
177 lines
5.9 KiB
Python
"""PDPL Compliance — final readiness check before Public Launch.
|
|
|
|
Saudi Personal Data Protection Law (PDPL) compliance check covering:
|
|
- Data residency
|
|
- Opt-in audit per channel
|
|
- Breach notification readiness (72-hour rule)
|
|
- DPA template availability
|
|
- Privacy policy bilingual publication
|
|
- SDAIA registration status (if applicable)
|
|
- Data retention policy enforcement
|
|
|
|
Deterministic — no I/O, no LLM. State is passed in as dict.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, asdict
|
|
from typing import Any, Mapping
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PDPLCheck:
|
|
key: str
|
|
name_ar: str
|
|
description_ar: str
|
|
severity: str # "critical" | "high" | "medium"
|
|
|
|
|
|
PDPL_CHECKS: tuple[PDPLCheck, ...] = (
|
|
PDPLCheck(
|
|
key="data_residency_saudi",
|
|
name_ar="إقامة البيانات في السعودية",
|
|
description_ar="بيانات العملاء مخزنة في region سعودي أو لدى شريك سعودي معتمد",
|
|
severity="critical",
|
|
),
|
|
PDPLCheck(
|
|
key="whatsapp_opt_in_audit",
|
|
name_ar="تدقيق opt-in لـ WhatsApp",
|
|
description_ar="كل رقم واتساب فيه opt-in موثّق قبل الإرسال",
|
|
severity="critical",
|
|
),
|
|
PDPLCheck(
|
|
key="email_opt_in_audit",
|
|
name_ar="تدقيق opt-in لـ Email",
|
|
description_ar="كل بريد إلكتروني فيه opt-in موثّق أو جاء عبر website form",
|
|
severity="high",
|
|
),
|
|
PDPLCheck(
|
|
key="breach_notification_72h_ready",
|
|
name_ar="جاهزية إبلاغ التسريب خلال 72 ساعة",
|
|
description_ar="عند تسريب بيانات: إبلاغ SDAIA + العملاء المتأثرين خلال 72 ساعة",
|
|
severity="critical",
|
|
),
|
|
PDPLCheck(
|
|
key="dpa_template_published",
|
|
name_ar="نشر نموذج DPA",
|
|
description_ar="نموذج Data Processing Agreement عربي/إنجليزي متاح للعملاء",
|
|
severity="high",
|
|
),
|
|
PDPLCheck(
|
|
key="privacy_policy_bilingual",
|
|
name_ar="سياسة الخصوصية ثنائية اللغة",
|
|
description_ar="Privacy Policy منشورة بالعربية والإنجليزية على dealix.me",
|
|
severity="critical",
|
|
),
|
|
PDPLCheck(
|
|
key="data_retention_policy",
|
|
name_ar="سياسة احتفاظ البيانات",
|
|
description_ar="بيانات الـ leads غير المتفاعلين تُحذف بعد 90 يوم",
|
|
severity="high",
|
|
),
|
|
PDPLCheck(
|
|
key="trace_redaction_active",
|
|
name_ar="إخفاء PII من traces",
|
|
description_ar="Trace Redactor مفعّل ويغطي email/phone/national_id/passport",
|
|
severity="critical",
|
|
),
|
|
PDPLCheck(
|
|
key="action_ledger_audit",
|
|
name_ar="سجل الأفعال (Action Ledger)",
|
|
description_ar="كل external action مسجّل مع who/what/when/approval_id",
|
|
severity="high",
|
|
),
|
|
PDPLCheck(
|
|
key="consent_revocation_path",
|
|
name_ar="مسار إلغاء الموافقة",
|
|
description_ar="العميل يقدر يلغي opt-in عبر link/email/WhatsApp بدون احتكاك",
|
|
severity="medium",
|
|
),
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class PDPLReport:
|
|
overall_status: str # "compliant" | "needs_fixes" | "non_compliant"
|
|
score_passed: int
|
|
score_total: int
|
|
critical_failures: list[Mapping[str, Any]]
|
|
high_failures: list[Mapping[str, Any]]
|
|
medium_failures: list[Mapping[str, Any]]
|
|
check_results: list[Mapping[str, Any]]
|
|
summary_ar: str
|
|
next_actions_ar: list[str]
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return asdict(self)
|
|
|
|
|
|
def compute_pdpl_compliance(state: Mapping[str, Any]) -> PDPLReport:
|
|
"""Evaluate PDPL compliance.
|
|
|
|
Args:
|
|
state: dict mapping check key → bool (True = compliant).
|
|
Keys not in state default to False (non-compliant).
|
|
|
|
Returns:
|
|
PDPLReport with overall status, failures by severity, next actions.
|
|
"""
|
|
results: list[dict[str, Any]] = []
|
|
critical_failures: list[dict[str, Any]] = []
|
|
high_failures: list[dict[str, Any]] = []
|
|
medium_failures: list[dict[str, Any]] = []
|
|
actions: list[str] = []
|
|
passed = 0
|
|
|
|
for check in PDPL_CHECKS:
|
|
ok = bool(state.get(check.key, False))
|
|
result = {
|
|
"key": check.key,
|
|
"name_ar": check.name_ar,
|
|
"passed": ok,
|
|
"severity": check.severity,
|
|
"description_ar": check.description_ar,
|
|
}
|
|
results.append(result)
|
|
if ok:
|
|
passed += 1
|
|
else:
|
|
if check.severity == "critical":
|
|
critical_failures.append(result)
|
|
actions.append(f"🛑 [CRITICAL] {check.name_ar} — {check.description_ar}")
|
|
elif check.severity == "high":
|
|
high_failures.append(result)
|
|
actions.append(f"⚠️ [HIGH] {check.name_ar}")
|
|
else:
|
|
medium_failures.append(result)
|
|
|
|
total = len(PDPL_CHECKS)
|
|
|
|
if critical_failures:
|
|
status = "non_compliant"
|
|
summary = (
|
|
f"🛑 NON-COMPLIANT — {len(critical_failures)} مشاكل critical. "
|
|
"لا تنتقل لـ Public Launch قبل إصلاحها."
|
|
)
|
|
elif high_failures:
|
|
status = "needs_fixes"
|
|
summary = (
|
|
f"⚠️ NEEDS FIXES — {len(high_failures)} مشاكل high. "
|
|
f"PDPL compliance score: {passed}/{total}."
|
|
)
|
|
else:
|
|
status = "compliant"
|
|
summary = f"✅ COMPLIANT — كل {total} فحوصات PDPL متحققة."
|
|
|
|
return PDPLReport(
|
|
overall_status=status,
|
|
score_passed=passed,
|
|
score_total=total,
|
|
critical_failures=critical_failures,
|
|
high_failures=high_failures,
|
|
medium_failures=medium_failures,
|
|
check_results=results,
|
|
summary_ar=summary,
|
|
next_actions_ar=actions,
|
|
)
|