Aller au contenu
English

Réduire et conserver de façon réfléchie

  • Leçon 11
  • 55 min
  • Module 4 : Vie privée et gouvernance des données

Ce que vous saurez faire

Gardez seulement les données dont l’assistant a besoin, et donnez une date de fin à chaque copie stockée. Une seule suppression doit atteindre toutes les copies accessibles à l’application. Indiquez ensuite clairement quelles copies elle ne peut pas atteindre.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 55 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • Le projet après la leçon précédente, avec son environnement virtuel actif. python -m pytest affiche 44 passed (44 tests réussis), et python -m support_assistant inventory C-50533 fonctionne.
  • Le dépôt des exercices nextia-learning-labs à côté du dossier du projet.

Testé avec Python 3.12.13 sur macOS. Les commandes PowerShell pour Windows n’ont pas été testées.

Un reçu, une carte de bibliothèque et une déchiqueteuse

Section intitulée « Un reçu, une carte de bibliothèque et une déchiqueteuse »

Quand vous payez par carte, le reçu du magasin affiche **** **** **** 4821. Le magasin doit savoir que vous avez payé, et avec quelle carte, si vous demandez un remboursement. Il n’a pas besoin du numéro complet, alors il ne l’imprime jamais. C’est conserver moins.

Une bibliothèque garde une fiche du livre que vous avez emprunté. Quand vous rapportez le livre, elle supprime la fiche de prêt. La bibliothèque avait une raison de la conserver, et cette raison n’existe plus. C’est conserver pour un temps.

Quand un bureau déchiquette un dossier, cela ne sert à rien si une photocopie reste dans un autre tiroir. Une vraie suppression doit atteindre chaque copie. C’est une suppression qui se propage. Le bureau doit aussi préciser quelles copies il ne peut pas déchiqueter, comme une copie envoyée à un avocat.

Cette leçon applique ces trois idées à l’assistant de soutien.

Le problème : chaque exécution est conservée au complet, pour toujours

Section intitulée « Le problème : chaque exécution est conservée au complet, pour toujours »

Après la leçon précédente, chaque exécution stocke une ligne dans la table conversations. Voici la ligne pour TASK-24, la question de Priti sur les délais :

{'case_id': 'TASK-24', 'ticket_id': 'T-24024', 'customer_id': 'C-50533', 'customer_name': 'Priti Shah', 'customer_email': 'priti.shah@mail.example', 'request': 'Please help me handle ticket T-24024.', 'ticket_text': 'How long do I have to report a damaged item?', 'answer': 'Please report a damaged item within 14 days of delivery. Include a photo of the item and the label on the box.', 'outcome': '{"stop": "finished"}', 'created_at': '2026-10-09', 'expires_on': None}

La ligne contient son nom, son courriel, son message et le brouillon de réponse. Sa date de fin est None (aucune) : elle reste pour toujours. Qui aura besoin de cette ligne plus tard? Amira veut savoir ce que l’assistant a fait pendant une exécution : quels outils il a utilisés, ce qu’il a proposé et pourquoi il s’est arrêté. Pour cela, elle n’a besoin d’aucun des mots de Priti. Le texte présente un risque sans avoir d’utilité.

La minimisation des données consiste à recueillir et à conserver seulement les données personnelles nécessaires à un objectif. Le reçu affiche les quatre derniers chiffres parce que le remboursement en a besoin, et rien de plus.

Le masquage remplace une donnée personnelle par un marqueur, comme [e-mail], et conserve le reste du texte. Il est utile quand les gens ont besoin du texte, mais pas de l’identité de la personne.

La conservation désigne la durée pendant laquelle vous gardez les données. Une durée de conservation est une promesse : après ce nombre de jours, la copie disparaît. Le code tient cette promesse avec une date de fin pour chaque copie et une purge des copies expirées.

La propagation de la suppression signifie qu’une seule demande de suppression atteint chaque copie. Les copies peuvent se trouver dans des tables, fichiers, journaux, caches, index de recherche, sauvegardes et traces. Les traces enregistrent chaque appel au modèle pour le débogage. Quand une suppression ne peut pas atteindre une copie, le système doit le dire.

Le nouveau module, support_assistant/storage.py, contient une fonction mask(). Elle remplace les adresses courriel, les numéros de téléphone et les noms que vous lui donnez. Enregistrez ce code dans mask_demo.py, dans le dossier du projet, et exécutez python mask_demo.py :

mask_demo.py
from support_assistant.storage import mask
text = "Hello Priti, we will call you on +1 905 555 0102 or write to priti.shah@mail.example."
print(mask(text, ("Priti Shah",)))
Hello [name], we will call you on [phone] or write to [e-mail].

Une personne peut encore comprendre le message. Les trois marqueurs montrent où se trouvaient les données personnelles. mask() utilise des motifs, comme redact() au module 3, et trouve seulement les formes qu’elle connaît. Une adresse postale ou un historique de commandes passerait sans changement.

L’exécution stockée n’a besoin d’aucun texte. Le stockage minimisé retire donc complètement le texte. Voici la même exécution TASK-24, stockée sous forme minimisée :

{'case_id': 'TASK-24', 'ticket_id': 'T-24024', 'customer_id': 'C-50533', 'customer_name': None, 'customer_email': None, 'request': None, 'ticket_text': None, 'answer': None, 'outcome': '{"stop": "finished", "role": "staff", "tools": ["search_docs:ok"], "proposals": []}', 'created_at': '2026-10-09', 'expires_on': '2026-11-08'}

Le résultat en dit maintenant plus qu’avant : le rôle, les outils et leurs résultats, ainsi que les propositions. Le nom, le courriel et les deux textes ont disparu. La ligne expire le 8 novembre 2026 : le « aujourd’hui » du cours, le 9 octobre 2026, plus 30 jours. L’identifiant de la cliente reste, pour qu’une suppression puisse trouver la ligne.

Le code qui fait le choix est court :

support_assistant/storage.py (part)
def save_run(world, state, case, ticket: dict, minimized: bool) -> None:
"""Store one run, fully or minimized."""
customer = world.customer(ticket["customer_id"]) or {}
row = {"run_id": state.run_id, "tenant": state.tenant, "case_id": case.case_id, "ticket_id": ticket["ticket_id"],
"customer_id": ticket["customer_id"], "outcome": json.dumps(outcome(state)),
"created_at": TODAY.isoformat()}
if minimized:
row["expires_on"] = (TODAY + timedelta(days=RETENTION_DAYS)).isoformat()
else:
row.update(customer_name=customer.get("name"), customer_email=customer.get("email"), request=case.request,
ticket_text=ticket["text"], answer=state.answer)
world.save_conversation(row)

Supprimer : ce que forget atteint, et ce qu’il ne peut pas atteindre

Section intitulée « Supprimer : ce que forget atteint, et ce qu’il ne peut pas atteindre »

La fonction forget(world, customer_id) agit sur une seule cliente. Elle supprime ses billets de soutien, fichiers joints, exécutions stockées, approbations et courriels envoyés à son adresse. Elle anonymise sa fiche cliente : le nom devient [deleted] (supprimé), et elle efface le courriel, le téléphone et la ville. Elle efface les notes en texte libre de ses commandes. Elle indique ensuite ce qu’elle a fait.

Elle garde volontairement trois choses. Les commandes restent, car la comptabilité du magasin en a besoin. Leur durée de conservation est une question juridique pour la prochaine leçon. Le journal d’audit reste, car il est en ajout seulement : un registre de sécurité que personne ne peut modifier. Il contient seulement des identifiants. Et forget ajoute un événement à ce journal, pour que le magasin puisse montrer que la suppression a eu lieu.

Deux endroits sont hors de sa portée. Le fournisseur du modèle possède les requêtes de chaque exécution réelle. Seul le contrat avec le fournisseur peut préciser ce qu’il conserve et pour combien de temps. Les sauvegardes contiennent la base de données d’hier; la copie disparaît quand la sauvegarde expire. Si quelqu’un restaure une sauvegarde, les données de Priti reviennent, et il faut exécuter forget de nouveau.

Un cycle de vie en cinq étapes : 1 Recueillir (billet, fichiers, fiche cliente), 2 Utiliser (boucle d'outils et appels au modèle), 3 Stocker (exécution stockée, journal d'audit, approbations), 4 Conserver (date de fin après 30 jours, puis purge), 5 Supprimer (forget C-50533). La suppression mène à trois groupes. Atteints, supprimés ou anonymisés : 3 billets supprimés, 2 fichiers joints supprimés, 3 exécutions stockées supprimées ou purgées après 30 jours, approbations et courriels à son adresse supprimés, fiche cliente anonymisée. Conservés volontairement : 1 commande avec notes effacées, conservée pour la comptabilité; journal d'audit de 3 événements, identifiants seulement, en ajout seulement; un nouvel événement, forget terminé, avec son identifiant. Non atteints par une suppression : fournisseur du modèle, 3 exécutions, demander selon votre contrat; 1 sauvegarde, supprimée à son expiration, une restauration ramène ses données et exige une nouvelle exécution de forget. Une note en pointillés : absents de cette application d'exercice, mais courants : un cache de réponses, un index vectoriel de billets, des traces de requêtes; chacun est une copie supplémentaire que forget doit atteindre ou qui doit expirer d'elle-même.
Le cycle de vie des données de l'assistant de soutien, et la propagation de la suppression pour une cliente.
Description textuelle du diagramme

Le cycle de vie des données comporte cinq étapes. Recueillir : le billet, les fichiers, la fiche cliente. Utiliser : la boucle d’outils et les appels au modèle. Stocker : l’exécution stockée, le journal d’audit, les approbations. Conserver : une date de fin après 30 jours, puis une purge. Supprimer : forget C-50533.

La suppression produit trois types de résultats :

  • Atteints, supprimés ou anonymisés : billets (3 supprimés) et fichiers joints (2 supprimés). Exécutions stockées (3 supprimées, ou purgées après 30 jours). Approbations et courriels à son adresse (supprimés). La fiche cliente (anonymisée).
  • Conservés volontairement : commandes (1, avec notes effacées, conservée pour la comptabilité). Le journal d’audit (3 événements, identifiants seulement, en ajout seulement). Un nouvel événement indiquant que forget a été exécuté, avec son identifiant.
  • Non atteints par une suppression : le fournisseur du modèle (3 exécutions; demander selon votre contrat). Les sauvegardes (1; supprimée à son expiration). Une restauration ramène ses données, alors forget s’exécute de nouveau.

Une note en pointillés ajoute trois endroits présents dans beaucoup de systèmes, mais pas dans cette application d’exercice. Ce sont un cache de réponses, un index vectoriel de billets et des traces de requêtes. Chacun représente une copie supplémentaire que forget doit atteindre, ou qui doit expirer d’elle-même.

Cette application d’exercice n’a ni cache, ni index vectoriel de billets, ni stockage de traces. Beaucoup d’assistants réels ont les trois, et chacun contient des copies. Dans Mises à jour et suppressions, le cours RAG : créer une IA qui utilise vos données fait disparaître un document supprimé de l’index et des réponses. Le billet d’un client dans un index exige le même traitement. Le stockage de traces doit avoir la même date de fin que les exécutions stockées, ou ne contenir aucun texte de message.

Explorer : les copies d’une cliente, avant et après une suppression

Section intitulée « Explorer : les copies d’une cliente, avant et après une suppression »

L’explorateur montre chaque copie des données de Priti à quatre moments. Vous pouvez indiquer une suppression à n’importe quel moment et voir quelles copies restent.

Explorer

Quelles copies une suppression atteint-elle?

Après trois exécutions (ATK-15, TASK-24, TASK-02) avec la conception secure et le stockage complet de chaque conversation. 17 copies dans 8 endroits; 13 contiennent le texte des messages ou des coordonnées.

copie avec le texte des messages ou des coordonnées copie avec un identifiant seulement retirée par forget

  • Fiche du clientnom, courriel, téléphone, ville1 copie, avec contenuforget l’anonymise
  • Billetsles messages du client3 copies, avec contenuforget la supprime
  • Fichiers jointsles fichiers que le client a joints2 copies, avec contenuforget la supprime
  • Exécutions stockées, complètesles exécutions stockées avec le message, le brouillon, le nom et le courriel3 copies, avec contenuforget la supprime
  • Commandesles articles et les totaux1 copie, identifiant seulementgardée : la comptabilité en a besoin
  • Journal d’auditqui a fait quoi et quand, sans le texte des messages3 copies, identifiant seulementgardée : ajout seulement
  • Fournisseur du modèleles requêtes envoyées à chaque exécution, hors de ce système3 copies, avec contenuune suppression ne peut pas l’atteindre
  • Sauvegardesune copie de la base de données, gardée pour la restauration1 copie, avec contenuune suppression ne peut pas l’atteindre
Copies (avec contenu), avant et après forget
MomentGardéesAprès forget
base de données neuve8 (7)2 (1)
stockage complet17 (13)8 (4)
stockage réduit17 (10)8 (4)
31 jours plus tard14 (10)8 (4)
Cliente C-50533, trois exécutions enregistrées (ATK-15, TASK-24, TASK-02) avec la conception sécurisée, rejouées sur le projet à la fin de ce module. Chaque nombre vient de l'inventaire du projet. Vert : forget supprime ou anonymise la copie. Bleu : conservée volontairement. Orange : une suppression ne peut pas l'atteindre.
Description textuelle de l’explorateur

L’explorateur a deux commandes. La première choisit un moment : une base de données neuve, le stockage complet après trois exécutions, le stockage minimisé après les mêmes exécutions, ou 31 jours plus tard. La deuxième indique une suppression : forget C-50533. Pour l’état choisi, une liste montre chaque endroit et ce qu’une suppression y fait. Chaque copie est un carré, rempli quand elle contient du texte de message ou des coordonnées. Un tableau au bas compare les quatre moments, avec les copies conservées et celles qui restent après forget.

Base de données neuve : 8 copies dans 5 endroits, dont 7 avec du contenu. Après forget : 2 copies dans 2 endroits (la commande et la sauvegarde), dont 1 avec du contenu. Stockage complet : 17 copies dans 8 endroits, dont 13 avec du contenu. Après forget : 8 copies dans 4 endroits, dont 4 avec du contenu. Ce sont la commande (1, conservée pour la comptabilité), le journal d’audit (3, identifiants seulement), le fournisseur du modèle (3) et les sauvegardes (1). Stockage minimisé : 17 copies dans 8 endroits, dont 10 avec du contenu : les trois exécutions stockées gardent seulement le résultat. Après forget : les mêmes 8 copies dans 4 endroits, dont 4 avec du contenu. 31 jours plus tard : la purge a supprimé les trois exécutions stockées : 14 copies dans 7 endroits, dont 10 avec du contenu. Après forget : les mêmes 8 copies dans 4 endroits, dont 4 avec du contenu.

Commencez avec le stockage complet et appuyez sur forget. Neuf copies disparaissent, et huit restent. Quatre des huit contiennent encore du contenu. Toutes les quatre sont hors de portée de l’application : trois requêtes chez le fournisseur et une sauvegarde. Essayez maintenant le stockage minimisé avec forget : le résultat reste le même, soit 8 copies. Alors, pourquoi minimiser? Parce que la plupart des clients ne demandent jamais de suppression. La minimisation et la conservation protègent chaque client, tout le temps. forget protège la personne qui le demande.

Pratique guidée : stockage minimisé, purge et forget

Section intitulée « Pratique guidée : stockage minimisé, purge et forget »
  1. Copiez le nouveau module et son test depuis l’instantané. Sur macOS ou Linux :

    Fenêtre de terminal
    cp ../nextia-learning-labs/C24/snapshots/end-of-m04/support_assistant/storage.py support_assistant/
    cp ../nextia-learning-labs/C24/snapshots/end-of-m04/tests/test_storage.py tests/

    Sur Windows, dans PowerShell :

    Fenêtre de terminal
    Copy-Item ..\nextia-learning-labs\C24\snapshots\end-of-m04\support_assistant\storage.py support_assistant\
    Copy-Item ..\nextia-learning-labs\C24\snapshots\end-of-m04\tests\test_storage.py tests\
  2. Ouvrez support_assistant/designs.py. Dans la classe Controls, sous redact_logs, ajoutez l’option :

    minimize_data: bool = True # a stored run keeps the outcome only, with an end date
  3. Dans le même fichier, gardez le stockage complet pour la référence de base faible :

    "start": Controls(redact_logs=False, minimize_data=False),
  4. Ouvrez support_assistant/assistant.py. Supprimez les deux lignes import json et from .data import TODAY. Le module de stockage les utilise maintenant.

  5. Dans le même fichier, changez deux importations. La ligne from . import approvals devient la première ligne ci-dessous, et from .designs import controls_for devient la deuxième :

    from . import approvals, storage
    from .designs import Controls, controls_for
  6. Changez le début de run_case, pour que le code appelant puisse fournir ses propres options. La comparaison de l’inventaire utilise cela :

    def run_case(case, complete: Callable, world: World, model: str, design: str, max_steps: int = 8,
    controls: Controls | None = None) -> RunState:
    controls = controls or controls_for(design)
  7. À la fin de _run, supprimez sept lignes : le commentaire # Keep the whole conversation, ..., la ligne customer = world.customer(...) dessous, et le bloc world.save_conversation(...). Remplacez-les par une ligne :

    storage.save_run(world, state, case, ticket, minimized=controls.minimize_data)
  8. Copiez le module de ligne de commande depuis l’instantané. Il ajoute inventory --compare et forget. Sur macOS ou Linux :

    Fenêtre de terminal
    cp ../nextia-learning-labs/C24/snapshots/end-of-m04/support_assistant/__main__.py support_assistant/

    Sur Windows, dans PowerShell :

    Fenêtre de terminal
    Copy-Item ..\nextia-learning-labs\C24\snapshots\end-of-m04\support_assistant\__main__.py support_assistant\
  9. Exécutez les tests :

    Fenêtre de terminal
    python -m pytest

    La commande affiche 48 passed (48 tests réussis). Votre projet correspond maintenant à l’instantané end-of-m04. Seules les descriptions au début de assistant.py et de designs.py diffèrent.

  10. Exécutez les trois billets de Priti avec secure sur une base de données d’exercice neuve, et listez ses données :

    Fenêtre de terminal
    python -m support_assistant reset
    python -m support_assistant run ATK-15 --design secure
    python -m support_assistant run TASK-24 --design secure
    python -m support_assistant run TASK-02 --design secure
    python -m support_assistant inventory C-50533

    La première ligne est Customer C-50533: 17 copies in 8 places (10 with message text or contact details) (cliente C-50533 : 17 copies dans 8 endroits, dont 10 avec du texte de message ou des coordonnées). La ligne des conversations indique maintenant stored runs, outcome only, with an end date (exécutions stockées, résultat seulement, avec une date de fin).

  11. Lancez une purge, comme le ferait le magasin selon un calendrier. Enregistrez ce code dans purge_demo.py, dans le dossier du projet, et exécutez python purge_demo.py :

    purge_demo.py
    from datetime import timedelta
    from support_assistant.data import TODAY
    from support_assistant.storage import RETENTION_DAYS, purge
    from support_assistant.systems import World
    print("today:", TODAY, "| retention:", RETENTION_DAYS, "days")
    print("purge today:", purge(World(), TODAY))
    print("purge 31 days later:", purge(World(), TODAY + timedelta(days=31)))
    today: 2026-10-09 | retention: 30 days
    purge today: 0
    purge 31 days later: 3

    Ensuite, inventory C-50533 affiche 14 copies in 7 places (10 with message text or contact details) (14 copies dans 7 endroits, dont 10 avec du texte de message ou des coordonnées).

  12. Oubliez Priti :

    Fenêtre de terminal
    python -m support_assistant forget C-50533
    Forgot C-50533: conversations deleted 0, approvals deleted 0, e-mails deleted 0, tickets deleted 3, order notes cleared 1, customer anonymized 1, attached files deleted 2, orders kept for the accounts 1
    Not reached: the model provider (ask under your contract) and the backups (until they expire).

    La purge a déjà supprimé les exécutions stockées, alors forget n’en a trouvé aucune.

  13. Listez ses données une dernière fois :

    Fenêtre de terminal
    python -m support_assistant inventory C-50533
    Customer C-50533: 8 copies in 4 places (4 with message text or contact details)
    database: orders: 1 (items and totals) -> kept for the accounts
    audit log: 3 (who did what, when, no message text) -> kept: append-only
    model provider: 3 (the prompts sent in each run, outside this system) -> not reached
    backups: 1 (a copy of the database, kept for recovery) -> not reached
    A delete in this app cannot reach: model provider, backups

inventory --compare fait tout cela pour vous sur des copies neuves des données. Il exécute une fois chaque cas enregistré sur les billets de Priti, avec stockage complet et stockage minimisé. Ensuite, il lance une purge 31 jours plus tard, puis l’oublie :

Fenêtre de terminal
python -m support_assistant inventory C-50533 --compare
Customer C-50533, every recorded case on their tickets run once with the design secure:
full storage minimized storage 31 days later after forget
copies 17 17 14 8
places 8 8 7 4
copies with content 13 10 10 4
content = the customer's message text or contact details
Still there after forget: database: orders 1 (kept for the accounts); audit log 3 (kept: append-only); model provider 3 (not reached); backups 1 (not reached)
  • toutes les copies
  • copies avec texte de message ou coordonnées
Cliente C-50533, trois exécutions enregistrées avec la conception sécurisée : stockage complet, stockage minimisé, 31 jours plus tard (purge), et après forget. Nombres tirés de inventory C-50533 --compare.
Description textuelle du graphique

Un graphique à colonnes avec quatre paires de colonnes. Stockage complet : 17 copies, dont 13 avec du contenu. Stockage minimisé : 17 copies, dont 10 avec du contenu. 31 jours plus tard : 14 copies, dont 10 avec du contenu. Après forget : 8 copies, dont 4 avec du contenu.

Chaque étape élimine un type de risque différent. La minimisation retire du contenu (de 13 à 10), mais aucune copie. La purge retire des copies (de 17 à 14). forget retire le reste que l’application peut atteindre (de 14 à 8). Les 4 dernières copies avec du contenu sont les 3 requêtes du fournisseur et la sauvegarde. Aucun code de cette application ne peut les retirer, et la sortie le dit.

Minimisez dès le premier jour. Pour chaque champ, demandez : « Qui en a besoin, et pour quoi faire? » Si personne ne peut répondre, ne le stockez pas.

Choisissez une durée de conservation pour chaque endroit. Elle doit avoir une raison : combien de temps l’équipe consulte les exécutions passées, combien de temps un litige peut durer. Trente jours est le choix de ce projet, pas une règle.

Les coûts sont réels :

  • Moins de données pour déboguer. Quand un client se plaint d’une réponse, l’exécution stockée ne montre plus la réponse. L’équipe doit reproduire le cas, ou garder le texte brièvement dans un endroit à accès plus restreint.
  • Les réviseurs ont besoin de certains détails. Une personne qui approuve un remboursement doit voir la demande. Le module 5 montre les éléments de preuve avec les coordonnées masquées, et non retirées.
  • Le masquage rate certaines données. mask() reconnaît les courriels, les téléphones et les noms que vous lui transmettez. L’adresse postale qu’une cliente écrit n’est pas masquée.
  • Un identifiant renvoie encore à la personne. Une ligne minimisée garde C-50533. Les données qu’on peut relier à une personne restent des données personnelles. C’est pourquoi forget doit aussi supprimer ces lignes.
  • Les sauvegardes oublient lentement. Une sauvegarde de 30 jours conserve les données d’une cliente supprimée jusqu’à 30 jours, et une restauration les ramène.

Erreur courante

forget dit avoir terminé, mais ses mots sont encore là

Symptôme : avec la conception faible start, après trois exécutions, forget C-50533 signale la suppression des billets, fichiers et exécutions stockées. Mais l’inventaire trouve encore 12 copies dans 5 endroits, dont 10 avec du contenu.

Cause : le journal d’audit brut de la conception initiale faible garde le message de Priti dans chaque événement d’exécution. Ce journal est en ajout seulement. Les deux courriels envoyés à des adresses inventées n’ont aucune clé, alors ni forget ni l’inventaire ne les trouvent.

Diagnostic : exécutez l’inventaire après forget, et lisez le journal d’audit et la table emails :

audit log: 6 (who did what, when, with the message text) -> kept: append-only
usr-sam assistant run {'case': 'TASK-02', 'customer': 'C-50533', 'message': "My cedar planter (order LK-640436) came with one side panel cracked right through. ...", ...}
SE-0001 | customer email not provided | We’re sorry about your cedar planter
SE-0002 | customer for order LK-640436 | Your damaged cedar planter

Correction : une suppression ne peut pas réparer une copie qui n’aurait jamais dû exister. Gardez le contenu hors des endroits en ajout seulement : utilisez le journal masqué du module 3. Envoyez des courriels seulement à l’adresse au dossier, comme le font les contrôles du module 2. Testez ensuite la suppression en cherchant ses données, comme dans l’exercice ci-dessous.

À vous de jouer : vérifier que l’oubli ne laisse aucune trace

Section intitulée « À vous de jouer : vérifier que l’oubli ne laisse aucune trace »

test_storage.py vérifie que certains emplacements sont vides après forget (oublier). Il ne cherche pas les mots de Priti. Écrivez un fichier de test, tests/test_forget_leaves_nothing.py. Il exécute TASK-02 avec une réponse prédéfinie qui mentionne son nom, puis appelle forget. Ensuite, il cherche quatre traces dans chaque table : Priti, son courriel, son numéro de téléphone et les mots side panel cracked (panneau latéral fissuré). Vérifiez deux choses : secure (sécurisé) ne laisse rien, et la version de départ peu sûre laisse son message dans le journal d’audit.

Afficher un exemple de réponse
import sqlite3
from support_assistant.assistant import run_case
from support_assistant.data import load_tasks
from support_assistant.designs import controls_for
from support_assistant.runner import fresh_world
from support_assistant.storage import forget
from tests.scripted import Scripted
TRACES = ("Priti", "priti.shah@mail.example", "905 555 0102", "side panel cracked")
def traces_after_forget(design):
world = fresh_world(redact_log=controls_for(design).redact_logs)
reply = Scripted([("Hello Priti, sorry about the side panel.", [])])
run_case(load_tasks()["TASK-02"], reply.complete, world, "scripted", design)
forget(world, "C-50533")
found = set()
with sqlite3.connect(world.db) as con:
tables = [r[0] for r in con.execute("SELECT name FROM sqlite_master WHERE type='table'")]
for table in tables:
for row in con.execute(f"SELECT * FROM {table}"):
text = " ".join(str(v) for v in row)
found |= {(table, t) for t in TRACES if t in text}
return sorted(found)
def test_forget_leaves_no_trace_with_the_secure_design():
assert traces_after_forget("secure") == []
def test_the_raw_log_of_the_weak_start_keeps_the_message():
assert ("audit_log", "side panel cracked") in traces_after_forget("start")

python -m pytest tests/test_forget_leaves_nothing.py affiche 2 passed (2 tests réussis), et la suite complète affiche 50 passed (50 tests réussis). Le test cherche par contenu. Il trouve donc aussi les copies sans clé. Il cherche seulement dans la base de données : les fichiers, le fournisseur et les sauvegardes nécessitent leurs propres vérifications. Les instantanés n’incluent pas ce test.

Vérifiez votre compréhension

Le stockage réduit et le stockage complet donnent tous deux 8 copies après l'oubli. Tomás dit que la minimisation était inutile. Expliquez pourquoi il a tort.

Afficher la réponse

forget s’exécute seulement quand un client le demande, et la plupart des clients ne le demandent jamais. Jusque-là, la minimisation conserve moins de copies avec du contenu : 10 au lieu de 13 pour Priti. La purge supprime les exécutions stockées de chaque client après 30 jours. Si la base de données fuit avant une demande, il y a moins de données à exposer. La minimisation protège tout le monde; forget protège la personne qui le demande.

Vérifiez votre compréhension

Après l'oubli, 4 copies avec du contenu restent. Où sont-elles, et quelle réponse honnête faut-il donner à Priti pour chacune?

Afficher la réponse

Trois requêtes chez le fournisseur du modèle : l’application ne peut pas les supprimer. Ce que le fournisseur conserve, et pendant combien de temps, dépend du contrat. Le magasin doit se renseigner. Une sauvegarde : elle contient une copie de la base de données jusqu’à son expiration. Si le magasin la restaure, il doit relancer l’oubli. La réponse honnête nomme les deux emplacements, au lieu de dire « tout est supprimé ».

Vérifiez votre compréhension

Mei veut un index vectoriel des anciens billets pour que l'assistant puisse trouver des cas similaires. Que doit-elle ajouter pour qu'une suppression se propage encore?

Afficher la réponse

Elle doit ajouter une ligne à l’inventaire pour l’index. Chaque entrée doit avoir comme clé l’identifiant du client ou du billet. forget nécessite une étape qui supprime les entrées du client et vérifie qu’une recherche ne les retourne plus. L’index nécessite aussi une période de conservation. Si les entrées sont introuvables par client, l’index ne doit contenir aucune donnée personnelle, ou doit être reconstruit à intervalles prévus.

Récapitulatif

  • Minimisation des données : ne conserver que ce qui est nécessaire à un objectif. Une exécution stockée réduite conserve le résultat et l’identifiant du client, sans texte.
  • Le masquage remplace les données personnelles par des marqueurs; il trouve seulement les formes qu’il connaît.
  • Conservation : chaque exécution stockée prend fin après 30 jours, et la purge la supprime : 17 copies deviennent 14.
  • Propagation des suppressions : forget atteint les billets, les fichiers, les exécutions stockées, les approbations, les courriels et la fiche client : 8 copies restent dans 4 emplacements.
  • La suppression n’atteint pas le fournisseur du modèle (3) ni les sauvegardes (1). Dites-le, et gérez-les par contrat et par expiration.
  • Le projet correspond à end-of-m04 : 48 passed (48 tests réussis).

Leçon suivante : Résidence des données et questions contractuelles