Tous les articles

Un tier de données public/privé depuis un seul pipeline

25 juin 20266 min de lecture
Le problème n'était pas de produire un export de base de données : ça, un pipeline ETL classique sait déjà le faire. Le problème était que ce même export devait exister sous deux formes distinctes, une que n'importe qui peut cloner et lancer localement, une autre réservée à une poignée de personnes autorisées, sans dupliquer la logique d'extraction ni maintenir deux pipelines qui divergent avec le temps.

Le contexte concret : un ETL qui dump périodiquement l'état d'un jeu live dans une base Postgres (effets, sorts, objets, et autres tables de données dérivées d'un format binaire source). Une web-app applicative consomme ensuite ce dump pour peupler sa propre base de développement. Question simple en apparence : comment distribuer ce dump à des développeurs externes qui contribuent au projet, sans exposer certaines catégories de données pas encore prêtes à être publiques ?

Deux saveurs, un seul dump source

La solution qui a émergé n'est pas deux pipelines séparés mais une seule extraction complète, suivie d'une dérivation.

  1. 1

    Dump complet

    Le pipeline dump toujours la totalité des données dans un premier fichier : c'est la saveur privée, complète, sans filtre.
  2. 2

    Filtrage

    À partir de ce même fichier, un filtre applique une allowlist et produit un second fichier : la saveur publique.

Le point important, c'est le sens du filtrage. Concrètement, ça veut dire que quand une nouvelle catégorie d'objets apparaît dans le dump (un nouveau type de cosmétique, un nouvel ensemble de contenus), elle n'atterrit pas automatiquement dans la saveur publique.

Liste noire

La liste dit "voici ce qu'il faut retirer". L'oubli laisse fuiter par défaut : un nouveau contenu non listé sort automatiquement.

Liste blanche (retenue)

La liste dit "voici ce qui est autorisé à sortir". Tout le reste est exclu par défaut : un nouveau contenu reste absent tant que quelqu'un ne l'a pas explicitement ajouté.

C'est la direction d'erreur qu'on veut quand l'enjeu est de ne pas publier du contenu non finalisé.

Le filtre lui-même reste un détail d'implémentation : un script qui lit le dump ligne par ligne et ne laisse passer que les lignes dont l'identifiant appartient à la liste, pour les tables concernées. Tout le reste du dump (schéma, séquences, tables non sensibles) traverse sans modification. Ce qui compte dans le pattern, ce n'est pas ce script précis mais l'idée que le filtrage se fait en aval d'un seul dump source, jamais en dupliquant la requête d'extraction.

Les releases comme CDN du pauvre

Une fois les deux fichiers produits, il faut les distribuer. Pas besoin d'un CDN dédié ni d'un bucket de stockage objet : les releases GitHub font très bien l'affaire pour ce volume et cette fréquence de publication. Chaque release est taguée avec la version de la source de données, et porte un unique asset (le dump compressé).

La distinction entre les deux saveurs se joue sur deux axes : le dépôt cible et un suffixe de tag.

Saveur publique

Tag data-v<version>, dépôt principal <org>/<projet-public>, accès ouvert à tous.

Saveur privée

Tag data-v<version>-private, dépôt restreint <org>/<projet-donnees-privees>, marquée comme prerelease.

Le flag prerelease n'est pas cosmétique : il signale que cette release n'est pas destinée à une consommation générale, même pour quelqu'un qui aurait accès au dépôt par erreur ou par curiosité. C'est une deuxième barrière, indépendante du contrôle d'accès du dépôt lui-même.

Le contrat côté consommateur

Côté web-app, la commande qui va chercher ces dumps pour peupler une base locale ne connaît pas la notion de "confidentiel" en tant que telle. Elle connaît une saveur et un dépôt, tous deux fournis par variables d'environnement, avec des valeurs par défaut qui pointent vers le cas public :

.env (web-app)
bash
SEED_FLAVOR=public                 # ou "private"
SEED_REPO=<org>/<projet-public>    # ou le repo restreint

Résoudre la bonne release revient alors à interroger l'API des releases du dépôt ciblé et à filtrer par motif de tag correspondant à la saveur demandée (se terminant par le suffixe pour le privé, ne s'en terminant pas pour le public). Un développeur externe qui ne fournit aucune variable obtient par construction la saveur publique du dépôt public. Un développeur autorisé sur le tier privé doit explicitement pointer vers l'autre dépôt et l'autre saveur, généralement via un jeton d'authentification qui n'existe que pour les personnes qui en ont besoin.

Ce qui rend ce contrat propre, c'est qu'il ne repose sur aucune logique cachée côté client : toute la décision d'autorisation vit dans "qui a accès à quel dépôt et à quel jeton", pas dans le code de la commande de seed. Le code de résolution est identique pour les deux tiers, seule la configuration change.

Pourquoi séparer plutôt que tout ouvrir

La tentation naturelle serait de tout publier et de laisser chacun filtrer ce qui l'intéresse côté client. Ça ne marche pas ici parce que la raison d'exclusion n'est pas un problème de volume ou de pertinence, c'est un problème de maturité du contenu. Une base de données issue de fichiers de jeu bruts contient inévitablement des artefacts qui n'ont jamais été destinés à sortir : du contenu en cours de finalisation, des entrées de test laissées par les outils internes de développement, des éléments retirés mais pas encore nettoyés de la source. Rien de tout ça n'a de valeur pour un contributeur externe.

Attention

Publier prématurément l'un de ces éléments peut avoir des conséquences (annonce non désirée, contenu incomplet visible avant l'heure) qu'aucun filtrage côté client ne peut réparer après coup.

La leçon générale

À retenir

Ce pattern dépasse largement le cas d'un dump de jeu. Chaque fois qu'un pipeline produit des données dérivées dont une partie doit rester à diffusion restreinte, la même structure s'applique : une seule extraction source, un filtrage par liste blanche fermée par défaut plutôt qu'ouverte par défaut, une distribution versionnée qui sert à la fois de canal et d'historique, et un flag de prerelease ou équivalent qui marque le tier interne indépendamment du contrôle d'accès au dépôt. Le contrat entre producteur et consommateur se réduit alors à quelques variables d'environnement (quelle saveur, quel dépôt, quel suffixe de tag), ce qui le rend testable et réutilisable sans jamais coupler le code du consommateur à la notion de confidentialité elle-même.