new-site/scripts/workers/services/consent_audit.py
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

119 lines
4.7 KiB
Python

"""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]