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>
119 lines
4.7 KiB
Python
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]
|