"""Consent Management Audit handler (LLM-based). Audits an organization's consent collection, storage, and management practices across digital and offline channels against CCPA, GDPR, TCPA, CAN-SPAM, and state-specific consent requirements. """ from __future__ import annotations import os from .base_handler import BaseServiceHandler SERVICE_SYSTEM_PROMPT = """You are a compliance analyst at Performance West Inc. generating a Consent Management Compliance Audit report. RULES: - Write in professional, clear business English - Reference applicable consent frameworks: CCPA/CPRA opt-out, GDPR Article 7, TCPA express written consent, CAN-SPAM, state biometric consent laws, etc. - Never provide legal advice — use "we recommend" not "you must" - For each finding: what was found, regulation, risk level (Low/Medium/High/Critical), remediation - Evaluate consent across all channels: web, mobile, email, phone, in-person - Assess consent records for completeness and auditability - Consider cookie consent, marketing consent, data processing consent, and sensitive data consent """ SECTIONS = [ { "name": "executive_summary", "prompt": ( "Write a 200-word executive summary of the consent management audit. " "Include scope of review, overall consent compliance posture, and " "highest-risk findings." ), }, { "name": "consent_framework_analysis", "prompt": ( "Map out the applicable consent requirements for this organization. " "Based on their industry, locations, and data practices, identify " "which consent frameworks apply (opt-in vs. opt-out, affirmative vs. " "implied, prior express written consent) and any conflicts between " "overlapping regulations." ), }, { "name": "collection_practices", "prompt": ( "Audit consent collection practices across all channels. For each " "channel (website forms, cookie banners, mobile app, email signup, " "phone, in-person): how is consent obtained, what disclosures are " "provided, is consent granular or bundled, pre-checked boxes, dark " "patterns assessment." ), }, { "name": "consent_records", "prompt": ( "Evaluate the organization's consent record management. Assess: " "what is recorded (timestamp, IP, version, scope), storage method, " "retrieval capability, ability to demonstrate consent was given, " "consent version tracking, and audit trail completeness." ), }, { "name": "withdrawal_and_revocation", "prompt": ( "Review consent withdrawal and revocation processes. Assess: ease " "of withdrawal (must be as easy as giving consent), processing " "timelines, downstream propagation to processors and partners, " "preference center functionality, and universal opt-out mechanisms." ), }, { "name": "remediation_plan", "prompt": ( "Provide a prioritized remediation plan for consent compliance gaps. " "For each finding: reference, risk level, recommended action, " "responsible party, timeline. Address quick wins (banner fixes) " "and longer-term improvements (consent management platform)." ), }, ] class ConsentAuditHandler(BaseServiceHandler): SERVICE_SLUG = "consent-audit" SERVICE_NAME = "Consent Management Audit" TEMPLATE_NAME = "consent_audit_template.docx" REQUIRES_LLM = True async def process(self, order_data: dict) -> list[str]: work_dir = self._make_work_dir() order_number = order_data["name"] context = self._extract_order_context(order_data) template_path = self._get_template_path() docx_filename = self._output_filename(order_number, "docx") docx_path = os.path.join(work_dir, docx_filename) variables = { "order_number": order_number, "customer_name": order_data.get("customer_name", ""), "date": __import__("datetime").datetime.now().strftime("%B %d, %Y"), "service_name": self.SERVICE_NAME, "company_size": order_data.get("custom_company_size", "N/A"), "industry": order_data.get("custom_industry", "N/A"), "state": order_data.get("custom_state", "N/A"), } self._fill_template(template_path, variables, docx_path) sections = await self._generate_sections( SERVICE_SYSTEM_PROMPT, SECTIONS, context ) self._add_sections_to_doc(docx_path, sections) pdf_path = self._convert_to_pdf(docx_path) return [docx_path, pdf_path]