Les hooks Claude Code peuvent bloquer les commandes CLI dbt dangereuses avant leur exécution. La note sur les hooks existants couvre le blocage des modifications de fichiers vers des chemins protégés — cette note couvre le blocage des commandes CLI dbt dangereuses ciblant la production, comme l’exécution sur la mauvaise cible, le déclenchement de --full-refresh sur une table longue à reconstruire, ou l’exécution de dbt build sans sélecteur.
Le mécanisme clé est un hook PreToolUse qui inspecte la commande que Claude s’apprête à exécuter. Si elle correspond à un pattern dangereux, le hook sort avec le code 2, ce qui bloque l’exécution et fait remonter un message d’erreur à Claude. La sortie 0 laisse la commande passer. Tout autre code de sortie enregistre un avertissement mais ne bloque pas — une distinction qui prend les gens de court. Voir Hooks Claude Code pour le comportement complet des codes de sortie.
Le script de sécurité
Créez .claude/hooks/dbt-safety.sh :
#!/usr/bin/env bashset -euo pipefail
input=$(cat)command=$(echo "$input" | jq -r '.tool_input.command // empty')
# Est-ce une commande dbt ciblant la production ?if echo "$command" | grep -q "dbt" && echo "$command" | grep -q "\-\-target.*prod"; then
# Bloquer full-refresh en production if echo "$command" | grep -q "\-\-full-refresh"; then echo "Bloqué : --full-refresh en production. Exécutez cela manuellement si vous en êtes sûr." >&2 exit 2 fi
# Bloquer run/build sans sélecteur explicite if echo "$command" | grep -qE "dbt (run|build)" && ! echo "$command" | grep -qE "\-\-(select|models)"; then echo "Bloqué : dbt run en production nécessite un --select explicite" >&2 exit 2 fifi
exit 0Le hook lit l’entrée de l’outil depuis stdin en JSON, extrait la chaîne de commande et vérifie deux patterns :
-
--full-refreshen production — Toujours bloqué. Un full refresh reconstruit la table depuis zéro, supprimant toutes les données existantes d’abord. Sur une grande table de production, cela signifie des heures de reconstruction et des données potentiellement manquantes pendant la reconstruction. Si vous avez réellement besoin d’un full refresh en prod, exécutez-le manuellement en dehors de Claude Code. -
dbt runoudbt buildnon scopé en production — Bloqué sauf si--selectou--modelsest spécifié. Sans sélecteur, dbt exécute tout dans le projet. Sur une cible de production, c’est un défaut dangereux.
Enregistrement du hook
La configuration va dans .claude/settings.json :
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": ".claude/hooks/dbt-safety.sh" } ] } ] }}Le matcher Bash déclenche le hook sur chaque commande bash que Claude tente d’exécuter. Le hook lui-même effectue le filtrage — il n’inspecte que les commandes contenant dbt et --target.*prod. Tout le reste passe à la sortie 0.
Notez que les matchers sont sensibles à la casse. bash ne correspondra pas à Bash. Vérifiez les noms exacts des outils dans la sortie de Claude si vos hooks ne se déclenchent pas.
Extension du pattern
Le script de base couvre les deux erreurs de production les plus courantes, mais vous pouvez l’étendre pour les risques spécifiques à votre projet :
Bloquer dbt seed en production. Les seeds remplacent entièrement le contenu des tables. En production, cela peut écraser des tables de référence dont d’autres modèles dépendent :
if echo "$command" | grep -qE "dbt seed" && echo "$command" | grep -q "\-\-target.*prod"; then echo "Bloqué : dbt seed en production. Les seeds remplacent des tables entières." >&2 exit 2fiBloquer dbt run-operation en production. Les opérations personnalisées (comme les instructions drop dans les macros) peuvent être destructives :
if echo "$command" | grep -qE "dbt run-operation" && echo "$command" | grep -q "\-\-target.*prod"; then echo "Bloqué : dbt run-operation en production. Revoyez l'opération manuellement." >&2 exit 2fiExiger --defer sur les builds de production. Si votre workflow attend que les builds de production utilisent --defer avec un manifest de production (pour que les modèles inchangés ne soient pas reconstruits), vous pouvez l’imposer :
if echo "$command" | grep -qE "dbt (run|build)" && echo "$command" | grep -q "\-\-target.*prod"; then if ! echo "$command" | grep -q "\-\-defer"; then echo "Bloqué : les builds de production nécessitent --defer --state ./prod-manifest" >&2 exit 2 fifiPourquoi pas juste CLAUDE.md ?
Vous pourriez ajouter « ne jamais exécuter —full-refresh en production » à votre CLAUDE.md. Claude suivrait cette instruction la plupart du temps. Mais CLAUDE.md est probabiliste — une conversation complexe, une longue session ou un prompt particulièrement persuasif peut faire déprioriser les instructions.
Les hooks sont déterministes. Le script shell bloque soit la commande (sortie 2) soit la laisse passer (sortie 0). Il n’y a pas de place pour l’interprétation du LLM. Pour les opérations où le coût d’une erreur se mesure en heures d’indisponibilité ou en données de production corrompues, l’application déterministe vaut l’effort de configuration.
L’approche pratique : mettez la règle dans les deux endroits. CLAUDE.md empêche Claude d’essayer la commande dangereuse en premier lieu. Le hook l’intercepte si Claude essaie quand même. Défense en profondeur.
Versionnez vos hooks de sécurité
Placez .claude/hooks/ et .claude/settings.json dans git. Quand vous intégrez un nouveau membre d’équipe, il obtient automatiquement tous vos garde-fous de production. Quand quelqu’un dans l’équipe rencontre un nouveau pattern dangereux, il ajoute une vérification au script de sécurité partagé et tout le monde en bénéficie au prochain pull.
Ce pattern est une application de l’approche de revue en couches : détecter les opérations dangereuses au plus tôt dans le workflow.