Le Règlement Californien sur la Protection de la Vie Privée des Consommateurs (CCPA) impose des obligations strictes aux entreprises traitant des données personnelles. L'intégration de l'intelligence artificielle dans les processus de traitement des données nécessite une approche méticuleuse pour garantir la conformité réglementaire. Ce tutoriel détaille les stratégies techniques et les bonnes pratiques pour implémenter un pipeline de données CCPA-compliant avec des modèles d'IA.

CCPA Compliance : Tableau Comparatif des Approches

CritèreApproche Native CCPAIntégration API IA StandardSolutions Manuelles Traditionnelles
Temps de traitement des demandes d'accès15-30 minutes (automatisé)72 heures en moyenne5-10 jours ouvrés
Coût par demande supprimée$0.02-0.05 USD$0.15-0.50 USD$12-45 USD
Traçabilité des opérationsLogging complet natifDépend du providerDocumentation manuelle
Détection des données sensibles97.3% de précision (modèles NLP)Variable selon provider80-85% manuel
Conformité multi-juridictionnelleModule GDPR additif disponibleLimité à CCPA uniquementExtensible mais coûteux

Comprendre les Exigences CCPA pour le Traitement IA

La California Consumer Privacy Act (CCPA), effective depuis le 1er janvier 2020, octroie aux résidents californiens des droits spécifiques sur leurs données personnelles. Pour les systèmes d'intelligence artificielle, trois obligations principales émergent : le droit de savoir (quelles données sont collectées), le droit de supprimer (erasure right), et le droit de refuser (opt-out). L'architecture technique doit permettre une réponse automatisée à ces demandes tout en maintenant l'intégrité des modèles de machine learning.

Architecture CCPA-Compliant pour l'Inférence IA

Une architecture robuste pour le traitement CCPA des données via IA comprend plusieurs couches essentielles. Le middleware de conformité doit interceptor toutes les requêtes avant qu'elles n'atteignent les modèles, vérifier le statut des données dans un registre centralisé, et maintenir un audit trail complet de toutes les opérations. L'implémentation suivante démontre une architecture complète avec un système de scoring de confidentialité intégré.

Implémentation du Middleware de Conformité CCPA

#!/usr/bin/env python3
"""
CCPA Compliance Middleware pour Traitement IA
Gestion centralisée des droits des consommateurs californiens
"""

import hashlib
import json
import logging
from datetime import datetime, timedelta
from dataclasses import dataclass, asdict
from typing import Optional, List, Dict, Any
from enum import Enum
import redis
from sqlalchemy import create_engine, Column, String, DateTime, Boolean, JSON
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class DataSubjectStatus(Enum):
    ACTIVE = "active"
    OPTED_OUT = "opted_out"
    DELETED = "deleted"
    ANONYMIZED = "anonymized"

class RightType(Enum):
    ACCESS = "right_to_know"
    DELETE = "right_to_delete"
    OPT_OUT = "right_to_opt_out"
    CORRECT = "right_to_correct"
    LIMIT_USE = "right_to_limit_use"

@dataclass
class DataSubject:
    """Représente un sujet de données CCPA"""
    consumer_id: str
    email_hash: str
    status: DataSubjectStatus
    data_categories: List[str]
    consent_timestamp: Optional[datetime]
    deletion_timestamp: Optional[datetime]
    last_access_timestamp: Optional[datetime]
    processing_purposes: List[str]

@dataclass
class ComplianceRequest:
    """Requête de conformité CCPA"""
    request_id: str
    request_type: RightType
    consumer_id: str
    submitted_at: datetime
    verified_at: Optional[datetime]
    completed_at: Optional[datetime]
    status: str
    response_data: Optional[Dict[str, Any]]
    verification_method: str

class CCPARegistry:
    """Registre centralisé des droits des consommateurs"""
    
    def __init__(self, redis_host: str = "localhost", redis_port: int = 6379):
        self.redis_client = redis.Redis(
            host=redis_host, 
            port=redis_port, 
            decode_responses=True
        )
        self._setup_logging()
    
    def _setup_logging(self):
        self.logger = logging.getLogger("CCPA_Compliance")
        self.logger.setLevel(logging.INFO)
        handler = logging.StreamHandler()
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        handler.setFormatter(formatter)
        self.logger.addHandler(handler)
    
    def check_consumer_status(self, consumer_id: str) -> DataSubjectStatus:
        """Vérifie le statut actuel d'un consommateur"""
        status_key = f"ccpa:consumer:{consumer_id}:status"
        status = self.redis_client.get(status_key)
        
        if status is None:
            return DataSubjectStatus.ACTIVE
        
        return DataSubjectStatus(status)
    
    def register_data_collection(
        self, 
        consumer_id: str, 
        data_categories: List[str],
        purposes: List[str]
    ) -> bool:
        """Enregistre une nouvelle collecte de données"""
        try:
            consumer_data = {
                "consumer_id": consumer_id,
                "data_categories": json.dumps(data_categories),
                "processing_purposes": json.dumps(purposes),
                "collected_at": datetime.utcnow().isoformat(),
                "status": DataSubjectStatus.ACTIVE.value
            }
            
            pipe = self.redis_client.pipeline()
            pipe.hmset(f"ccpa:consumer:{consumer_id}:data", consumer_data)
            pipe.sadd(f"ccpa:consumers:active", consumer_id)
            pipe.execute()
            
            self.logger.info(f"Data collection registered for consumer {consumer_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"Failed to register data collection: {e}")
            return False
    
    def process_deletion_request(self, consumer_id: str) -> Dict[str, Any]:
        """Traite une demande de suppression CCPA"""
        self.logger.info(f"Processing deletion request for {consumer_id}")
        
        deletion_key = f"ccpa:consumer:{consumer_id}:deletion"
        
        # Vérifier si déjà supprimé
        if self.redis_client.exists(deletion_key):
            return {
                "status": "already_processed",
                "request_id": self.redis_client.get(deletion_key),
                "message": "Request previously processed"
            }
        
        # Générer identifiant de requête
        request_id = hashlib.sha256(
            f"{consumer_id}{datetime.utcnow().isoformat()}".encode()
        ).hexdigest()[:16]
        
        # Stocker la demande
        pipe = self.redis_client.pipeline()
        pipe.set(f"ccpa:consumer:{consumer_id}:status", DataSubjectStatus.DELETED.value)
        pipe.set(f"ccpa:consumer:{consumer_id}:deletion", request_id)
        pipe.srem(f"ccpa:consumers:active", consumer_id)
        pipe.sadd(f"ccpa:consumers:deleted", consumer_id)
        pipe.execute()
        
        return {
            "status": "deletion_initiated",
            "request_id": request_id,
            "estimated_completion": (datetime.utcnow() + timedelta(hours=24)).isoformat()
        }
    
    def get_consumer_data_inventory(self, consumer_id: str) -> Dict[str, Any]:
        """Génère un inventaire complet des données pour droit d'accès"""
        data_key = f"ccpa:consumer:{consumer_id}:data"
        
        if not self.redis_client.exists(data_key):
            return {"status": "not_found", "consumer_id": consumer_id}
        
        consumer_data = self.redis_client.hgetall(data_key)
        
        return {
            "consumer_id": consumer_id,
            "status": consumer_data.get("status"),
            "data_collected": json.loads(consumer_data.get("data_categories", "[]")),
            "processing_purposes": json.loads(consumer_data.get("processing_purposes", "[]")),
            "collected_at": consumer_data.get("collected_at"),
            "categories_under_ccpa": [
                "Identifiers (name, email, IP)",
                "Commercial information",
                "Internet activity",
                "Geolocation data",
                "Inferences from collected data"
            ]
        }

class ComplianceAuditLogger:
    """Système d'audit CCPA immutable"""
    
    def __init__(self, db_url: str):
        self.engine = create_engine(db_url)
        Base.metadata.create_all(self.engine)
        Session = sessionmaker(bind=self.engine)
        self.session = Session()
    
    def log_request(self, request: ComplianceRequest):
        """Enregistre une requête de conformité"""
        audit_entry = {
            "request_id": request.request_id,
            "request_type": request.request_type.value,
            "consumer_id": request.consumer_id,
            "submitted_at": request.submitted_at.isoformat(),
            "verified_at": request.verified_at.isoformat() if request.verified_at else None,
            "completed_at": request.completed_at.isoformat() if request.completed_at else None,
            "status": request.status,
            "verification_method": request.verification_method
        }
        
        self.logger.info(f"Audit log: {json.dumps(audit_entry)}")

Exemple d'utilisation

if __name__ == "__main__": registry = CCPARegistry(redis_host="localhost") # Enregistrement d'un nouveau consommateur registry.register_data_collection( consumer_id="consumer_12345", data_categories=["email", "browsing_history", "purchase_history"], purposes=["service_improvement", "personalization", "analytics"] ) # Vérification du statut status = registry.check_consumer_status("consumer_12345") print(f"Consumer status: {status.value}") # Inventaire des données (droit de savoir) inventory = registry.get_consumer_data_inventory("consumer_12345") print(f"Data inventory: {json.dumps(inventory, indent=2)}")

Intégration de la Vérification de Conformité dans les Requêtes IA

Après avoir configuré le registre centralisé CCPA, l'étape suivante consiste à intégrer les vérifications de conformité directement dans le pipeline d'inférence IA. Le middleware ci-dessous intercept toutes les requêtes vers les modèles de machine learning et vérifie automatiquement le statut du consommateur avant de procéder au traitement.

#!/usr/bin/env python3
"""
CCPA-Aware AI Inference Gateway
Interceptor de requêtes avec vérification de conformité intégrée
"""

import asyncio
import httpx
import jwt
from typing import Optional, Dict, Any, Callable
from functools import wraps
import time
from collections import defaultdict
import circuit_breaker

class CCAComplianceError(Exception):
    """Exception levée lors de violations de conformité CCPA"""
    def __init__(self, message: str, consumer_id: str, violation_type: str):
        super().__init__(message)
        self.consumer_id = consumer_id
        self.violation_type = violation_type

class RateLimitExceeded(Exception):
    """Exception pour dépassement du taux de requêtes CCPA"""
    pass

class ComplianceConfig:
    """Configuration des paramètres de conformité CCPA"""
    
    CCPA_RESPONSE_WINDOW_DAYS = 45
    VERIFICATION_GRACE_PERIOD_HOURS = 15
    MAX_REQUESTS_PER_DAY_PER_CONSUMER = 2
    ANONYMIZATION_BATCH_SIZE = 1000
    RETENTION_PERIOD_DAYS = 90
    
    # Catégories de données sensibles nécessitant protection
    SENSITIVE_DATA_CATEGORIES = [
        "social_security_number",
        "drivers_license",
        "financial_account",
        "health_information",
        "biometric_data",
        "precise_geolocation"
    ]

class CCPACompliantInferenceGateway:
    """
    Gateway d'inférence IA avec conformité CCPA native
    Intercepte et valide toutes les requêtes avant traitement
    """
    
    def __init__(
        self,
        base_url: str,
        api_key: str,
        registry: 'CCPARegistry',
        audit_logger: 'ComplianceAuditLogger'
    ):
        self.base_url = base_url
        self.api_key = api_key
        self.registry = registry
        self.audit_logger = audit_logger
        self.config = ComplianceConfig()
        
        # Rate limiting par consommateur
        self.request_counts: Dict[str, list] = defaultdict(list)
        
        # Circuit breaker pour résilience
        self.circuit_breaker = circuit_breaker.CircuitBreaker(
            failure_threshold=5,
            recovery_timeout=30
        )
    
    def _check_rate_limit(self, consumer_id: str) -> bool:
        """Vérifie les limites de requêtes CCPA"""
        now = time.time()
        cutoff = now - 86400  # 24 heures
        
        # Nettoyer les anciennes entrées
        self.request_counts[consumer_id] = [
            ts for ts in self.request_counts[consumer_id] 
            if ts > cutoff
        ]
        
        if len(self.request_counts[consumer_id]) >= self.config.MAX_REQUESTS_PER_DAY_PER_CONSUMER:
            return False
        
        self.request_counts[consumer_id].append(now)
        return True
    
    def _validate_consumer_request(self, consumer_id: str) -> Dict[str, Any]:
        """Validation complète d'une requête consommateur"""
        validation_result = {
            "valid": True,
            "warnings": [],
            "errors": []
        }
        
        # Vérifier le statut du consommateur
        status = self.registry.check_consumer_status(consumer_id)
        
        if status == DataSubjectStatus.DELETED:
            validation_result["valid"] = False
            validation_result["errors"].append({
                "code": "DATA_DELETED",
                "message": "Consumer data has been deleted per CCPA request"
            })
        
        elif status == DataSubjectStatus.OPTED_OUT:
            validation_result["warnings"].append({
                "code": "OPT_OUT_ACTIVE",
                "message": "Consumer has opted out of data sale"
            })
        
        # Vérifier rate limiting
        if not self._check_rate_limit(consumer_id):
            validation_result["valid"] = False
            validation_result["errors"].append({
                "code": "RATE_LIMIT_EXCEEDED",
                "message": f"Maximum {self.config.MAX_REQUESTS_PER_DAY_PER_CONSUMER} requests per day exceeded"
            })
        
        return validation_result
    
    async def inference_with_compliance(
        self,
        consumer_id: str,
        prompt: str,
        model: str = "gpt-4",
        max_tokens: int = 1000,
        **kwargs
    ) -> Dict[str, Any]:
        """
        Exécute une inférence IA avec vérification de conformité CCPA
        """
        # Étape 1: Validation de la requête
        validation = self._validate_consumer_request(consumer_id)
        
        if not validation["valid"]:
            raise CCPAComplianceError(
                message="Request validation failed",
                consumer_id=consumer_id,
                violation_type=validation["errors"][0]["code"]
            )
        
        # Étape 2: Log de la requête entrante
        request_log = {
            "consumer_id": consumer_id,
            "timestamp": time.time(),
            "model": model,
            "prompt_length": len(prompt),
            "validation_warnings": validation["warnings"]
        }
        
        # Étape 3: Exécuter l'inférence via circuit breaker
        try:
            result = await self.circuit_breaker.call(
                self._execute_inference,
                prompt=prompt,
                model=model,
                max_tokens=max_tokens,
                **kwargs
            )
            
            # Étape 4: Ajouter les métadonnées de conformité
            result["compliance_metadata"] = {
                "consumer_id": consumer_id,
                "data_status": self.registry.check_consumer_status(consumer_id).value,
                "warnings": validation["warnings"],
                "retention_period_days": self.config.RETENTION_PERIOD_DAYS
            }
            
            return result
            
        except circuit_breaker.CircuitBreakerError:
            return {
                "error": "Service temporarily unavailable",
                "retry_after": 30
            }
    
    async def _execute_inference(
        self,
        prompt: str,
        model: str,
        max_tokens: int,
        **kwargs
    ) -> Dict[str, Any]:
        """Exécute l'inférence auprès du provider IA"""
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
            "X-CCPA-Compliant": "true"
        }
        
        payload = {
            "model": model,
            "messages": [{"role": "user", "content": prompt}],
            "max_tokens": max_tokens,
            **kwargs
        }
        
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.post(
                f"{self.base_url}/chat/completions",
                headers=headers,
                json=payload
            )
            response.raise_for_status()
            return response.json()
    
    def generate_compliance_report(
        self,
        consumer_id: str,
        report_type: str = "full"
    ) -> Dict[str, Any]:
        """Génère un rapport de conformité pour un consommateur"""
        inventory = self.registry.get_consumer_data_inventory(consumer_id)
        status = self.registry.check_consumer_status(consumer_id)
        
        report = {
            "report_id": f"CCPA-{consumer_id}-{int(time.time())}",
            "generated_at": datetime.utcnow().isoformat(),
            "consumer_id": consumer_id,
            "data_status": status.value,
            "data_inventory": inventory,
            "rights_exercised": [],
            "processing_activities": []
        }
        
        if report_type == "full":
            report["personal_information_collected"] = inventory.get("data_collected", [])
            report["purposes_of_processing"] = inventory.get("processing_purposes", [])
            report["third_party_sharing"] = []
            report["retention_policy"] = {
                "period_days": self.config.RETENTION_PERIOD_DAYS,
                "deletion_schedule": "Automatic after retention period"
            }
        
        return report

Implémentation du pattern Circuit Breaker

class CircuitBreaker: def __init__(self, failure_threshold: int = 5, recovery_timeout: int = 30): self.failure_threshold = failure_threshold self.recovery_timeout = recovery_timeout self.failure_count = 0 self.last_failure_time: Optional[float] = None self.state = "closed" async def call(self, func: Callable, *args, **kwargs): if self.state == "open": if time.time() - self.last_failure_time > self.recovery_timeout: self.state = "half-open" else: raise CircuitBreakerError("Circuit breaker is open") try: result = await func(*args, **kwargs) if self.state == "half-open": self.state = "closed" self.failure_count = 0 return result except Exception as e: self.failure_count += 1 self.last_failure_time = time.time() if self.failure_count >= self.failure_threshold: self.state = "open" raise e

Démonstration d'utilisation

async def main(): # Initialisation du gateway registry = CCPARegistry() audit_logger = ComplianceAuditLogger("sqlite:///ccpa_audit.db") gateway = CCPACompliantInferenceGateway( base_url="https://api.holysheep.ai/v1", api_key="YOUR_HOLYSHEEP_API_KEY", registry=registry, audit_logger=audit_logger ) # Enregistrer un consommateur registry.register_data_collection( consumer_id="california_resident_001", data_categories=["identifiers", "browsing_history"], purposes=["customer_service", "service_improvement"] ) # Exécuter une inférence CCPA-compliant try: result = await gateway.inference_with_compliance( consumer_id="california_resident_001", prompt="Explain how CCPA affects data processing practices", model="gpt-4" ) print(f"Inference result: {result}") except CCPAComplianceError as e: print(f"Compliance error: {e.violation_type} - {e}") if __name__ == "__main__": asyncio.run(main())

Anonymisation et Pseudonymisation des Données

La CCPA autorise la conservation de données anonymisées pour l'entraînement et l'amélioration des modèles IA. Cette technique permet de maintenir la valeur analytique des données tout en les exemptant des obligations de suppression. L'implémentation suivante propose un système complet d'anonymisation avec conservation des caractéristiques statistiques utiles pour le machine learning.

#!/usr/bin/env python3
"""
Module d'Anonymisation CCPA pour Données d'Entraînement IA
Techniques de pseudonymisation preservant l'utilité statistique
"""

import hashlib
import hmac
import secrets
from typing import Dict, List, Tuple, Any, Optional
from dataclasses import dataclass
import numpy as np
from cryptography.fernet import Fernet
from collections import Counter
import re

@dataclass
class AnonymizationConfig:
    k_anonymity_threshold: int = 5
    l_diversity_threshold: int = 2
    epsilon_differential_privacy: float = 1.0
    tokenization_salt: Optional[bytes] = None

class DataAnonymizer:
    """
    Anonymiseur de données respectant les standards CCPA/CPRA
    Implémente k-anonymité, l-diversité et privacy différentielle
    """
    
    def __init__(self, config: AnonymizationConfig = None):
        self.config = config or AnonymizationConfig()
        if self.config.tokenization_salt is None:
            self.config.tokenization_salt = Fernet.generate_key()
        
        self.fernet = Fernet(self.config.tokenization_salt)
        self.token_mapping: Dict[str, str] = {}
        self.reverse_mapping: Dict[str, str] = {}
    
    def _generate_consistent_token(
        self, 
        original_value: str, 
        salt: bytes = None
    ) -> str:
        """Génère un token déterministe mais non réversible"""
        salt = salt or self.config.tokenization_salt
        hash_input = f"{salt.decode()}:{original_value}".encode()
        return hashlib.sha256(hash_input).hexdigest()[:16]
    
    def pseudonymize_identifiers(
        self, 
        data: Dict[str, Any]
    ) -> Dict[str, Any]:
        """
        Pseudonymise les identifiants directs (PII)
        Préserve la possibilité de relinkage avec clé de déchiffrement sécurisée
        """
        anonymized = data.copy()
        
        identifier_fields = [
            'email', 'phone', 'name', 'address', 
            'ssn', 'account_number', 'ip_address'
        ]
        
        for field in identifier_fields:
            if field in anonymized and anonymized[field]:
                original = str(anonymized[field])
                
                # Stocker le mapping sécurisé (à sauvegarder séparément)
                token = self._generate_consistent_token(original)
                self.token_mapping[token] = original
                
                anonymized[field] = f"PSEUDO_{token}"
        
        return anonymized
    
    def apply_k_anonymity(
        self, 
        records: List[Dict[str, Any]], 
        quasi_identifiers: List[str]
    ) -> List[Dict[str, Any]]:
        """
        Applique k-anonymité : chaque enregistrement est identique 
        à au moins k-1 autres sur les quasi-identifiants
        """
        # Grouper par quasi-identifiants
        groups: Dict[Tuple, List[int]] = {}
        
        for idx, record in enumerate(records):
            qi_values = tuple(
                record.get(qi, "NULL") for qi in quasi_identifiers
            )
            
            if qi_values not in groups:
                groups[qi_values] = []
            groups[qi_values].append(idx)
        
        # Filtrer les groupes avec moins de k membres
        filtered_records = []
        for qi_values, indices in groups.items():
            if len(indices) >= self.config.k_anonymity_threshold:
                filtered_records.extend([records[i] for i in indices])
        
        return filtered_records
    
    def apply_l_diversity(
        self,
        records: List[Dict[str, Any]],
        quasi_identifiers: List[str],
        sensitive_attribute: str
    ) -> List[Dict[str, Any]]:
        """
        Applique l-diversité : chaque groupe k-anonyme contient 
        au moins l valeurs distinctes pour l'attribut sensible
        """
        # Grouper par quasi-identifiants
        groups: Dict[Tuple, List[Dict]] = {}
        
        for record in records:
            qi_values = tuple(
                record.get(qi, "NULL") for qi in quasi_identifiers
            )
            
            if qi_values not in groups:
                groups[qi_values] = []
            groups[qi_values].append(record)
        
        # Filtrer selon l-diversité
        filtered_records = []
        for qi_values, group_records in groups.items():
            sensitive_values = [
                r.get(sensitive_attribute, "NULL") 
                for r in group_records
            ]
            
            if len(set(sensitive_values)) >= self.config.l_diversity_threshold:
                filtered_records.extend(group_records)
        
        return filtered_records
    
    def add_differential_privacy_noise(
        self, 
        numerical_values: List[float],
        sensitivity: float = 1.0
    ) -> List[float]:
        """
        Ajoute du bruit Laplace pour privacy différentielle
        Garantit que la suppression/ajout d'un enregistrement 
        n'affecte pas significativement le résultat
        """
        scale = sensitivity / self.config.epsilon_differential_privacy
        
        noisy_values = []
        for value in numerical_values:
            noise = np.random.laplace(0, scale)
            noisy_values.append(value + noise)
        
        return noisy_values
    
    def generalize_location(
        self, 
        latitude: float, 
        longitude: float,
        precision: int = 2
    ) -> Tuple[str, str]:
        """Généralise les coordonnées géographiques"""
        lat_generalized = round(latitude, precision)
        lon_generalized = round(longitude, precision)
        
        return (
            f"{lat_generalized}°N",
            f"{lon_generalized}°W"
        )
    
    def generalize_age(self, age: int) -> str:
        """Généralise l'âge en tranches"""
        if age < 18:
            return "minor"
        elif age < 25:
            return "18-24"
        elif age < 35:
            return "25-34"
        elif age < 45:
            return "35-44"
        elif age < 55:
            return "45-54"
        elif age < 65:
            return "55-64"
        else:
            return "65+"
    
    def anonymize_dataset(
        self,
        records: List[Dict[str, Any]],
        identifier_fields: List[str],
        quasi_identifiers: List[str],
        sensitive_field: str,
        numerical_fields: List[str]
    ) -> Dict[str, Any]:
        """
        Pipeline complet d'anonymisation CCPA-compliant
        """
        results = {
            "original_count": len(records),
            "anonymized_records": [],
            "metadata": {
                "k_anonymity": self.config.k_anonymity_threshold,
                "l_diversity": self.config.l_diversity_threshold,
                "differential_privacy_epsilon": self.config.epsilon_differential_privacy
            }
        }
        
        # Étape 1: Pseudonymisation des identifiants
        pseudonymized = [
            self.pseudonymize_identifiers(record) 
            for record in records
        ]
        
        # Étape 2: Généralisation des quasi-identifiants
        for record in pseudonymized:
            if 'age' in quasi_identifiers and 'age' in record:
                record['age'] = self.generalize_age(record['age'])
            
            if 'latitude' in record and 'longitude' in record:
                lat_gen, lon_gen = self.generalize_location(
                    record['latitude'], 
                    record['longitude']
                )
                record['latitude'] = lat_gen
                record['longitude'] = lon_gen
        
        # Étape 3: Application k-anonymité
        k_anonymized = self.apply_k_anonymity(
            pseudonymized, 
            quasi_identifiers
        )
        
        # Étape 4: Application l-diversité
        l_diversified = self.apply_l_diversity(
            k_anonymized,
            quasi_identifiers,
            sensitive_field
        )
        
        # Étape 5: Bruit différentiel sur les champs numériques
        for record in l_diversified:
            for num_field in numerical_fields:
                if num_field in record:
                    original_value = record[num_field]
                    record[num_field] = self.add_differential_privacy_noise(
                        [original_value]
                    )[0]
        
        results["anonymized_records"] = l_diversified
        results["final_count"] = len(l_diversified)
        results["privacy_utility_tradeoff"] = (
            results["final_count"] / results["original_count"]
        )
        
        return results
    
    def create_synthetic_training_data(
        self,
        anonymized_records: List[Dict[str, Any]],
        num_samples: int = 10000
    ) -> List[Dict[str, Any]]:
        """
        Génère des données synthétiques pour l'entraînement
        Basé sur les distributions statistiques des données anonymisées
        """
        synthetic_data = []
        
        # Extraire les distributions
        field_distributions = {}
        for record in anonymized_records:
            for key, value in record.items():
                if key not in field_distributions:
                    field_distributions[key] = []
                field_distributions[key].append(value)
        
        # Générer des échantillons synthétiques
        for _ in range(num_samples):
            synthetic_record = {}
            for field, values in field_distributions.items():
                if isinstance(values[0], (int, float)):
                    # Distribution normale pour les numériques
                    mean = np.mean(values)
                    std = np.std(values) if len(values) > 1 else 1
                    synthetic_record[field] = float(np.random.normal(mean, std))
                else:
                    # Distribution empirique pour les catégorielles
                    counter = Counter(values)
                    categories = list(counter.keys())
                    weights = [counter[c] / len(values) for c in categories]
                    synthetic_record[field] = np.random.choice(categories, p=weights)
            
            synthetic_data.append(synthetic_record)
        
        return synthetic_data

Démonstration

if __name__ == "__main__": # Configuration CCPA config = AnonymizationConfig( k_anonymity_threshold=5, l_diversity_threshold=2, epsilon_differential_privacy=0.8 ) anonymizer = DataAnonymizer(config) # Données d'exemple sample_records = [ {"email": "[email protected]", "age": 32, "latitude": 37.7749, "longitude": -122.4194, "purchase_amount": 150.00, "category": "electronics"}, {"email": "[email protected]", "age": 45, "latitude": 34.0522, "longitude": -118.2437, "purchase_amount": 89.99, "category": "clothing"}, {"email": "[email protected]", "age": 28, "latitude": 37.7749, "longitude": -122.4194, "purchase_amount": 220.50, "category": "electronics"}, {"email": "[email protected]", "age": 55, "latitude": 37.7749, "longitude": -122.4194, "purchase_amount": 45.00, "category": "books"}, {"email": "[email protected]", "age": 32, "latitude": 37.7749, "longitude": -122.4194, "purchase_amount": 180.00, "category": "electronics"}, {"email": "[email protected]", "age": 38, "latitude": 37.7749, "longitude": -122.4194, "purchase_amount": 95.00, "category": "home"}, {"email": "[email protected]", "age": 32, "latitude": 40.7128, "longitude": -74.0060, "purchase_amount": 310.00, "category": "electronics"}, {"email": "[email protected]", "age": 29, "latitude": 37.7749, "longitude": -122.4194, "purchase_amount": 55.00, "category": "sports"}, ] # Anonymisation complète results = anonymizer.anonymize_dataset( records=sample_records, identifier_fields=["email"], quasi_identifiers=["age", "latitude", "longitude"], sensitive_field="category", numerical_fields=["purchase_amount"] ) print(f"Original records: {results['original_count']}") print(f"Anonymized records: {results['final_count']}") print(f"Privacy-Utility ratio: {results['privacy_utility_tradeoff']:.2%}") print(f"\nSample anonymized record:") print(results['anonymized_records'][0] if results['anonymized_records'] else "No records after anonymization")

Gestion des Demandes de Suppression (Right to Delete)

Le droit à l'effacement constitue l'une des obligations les plus complexes pour les systèmes d'IA. Contrairement aux bases de données relationnelles simples, les modèles de machine learning stockent des représentations abstraites des données dans leurs paramètres. L'implémentation ci-dessous propose une approche multicouche combinant suppression logique, réentraînement incrémental, et techniques de machine unlearning pour les modèles hébergés.

#!/usr/bin/env python3
"""
CCPA Right to