claria.tools.sql-client 1.0.0-build.20260819.1

Build Information

Provenance Azure DevOps Pipeline
Owner kntera (Yan Boivin)
Date de compilation 2026-08-20 03:29:31 UTC
Version 1.0.0.20260819.1
SHA256 c459994b8934484f497073c13eb1e289a1d66b28

sql-client

Outil en ligne de commande qui exécute des requêtes SQL sur des bases SQL Server, MySQL et PostgreSQL, sous le contrôle d'une politique d'autorisation (allow / deny / redact). Conçu pour permettre à des agents d'opérer des bases de données en gardant l'humain aux commandes sur tout énoncé non couvert par la politique — même modèle de sécurité que restapi-client et ssh-client.


Contexte

Plutôt que d'exposer un client SQL brut (sqlcmd, mysql, psql) à un agent, sql-client s'intercale comme garde-fou : chaque script est analysé (découpage en énoncés, type et objets référencés de chacun), puis chaque énoncé — la combinaison base + type d'énoncé (SELECT, UPDATE, DELETE, …) + objet (table, vue, procédure) — est évalué contre une liste allow et une liste deny avant tout envoi. Le type d'énoncé joue le rôle de la méthode REST de restapi-client ; l'objet, celui du chemin d'URL. Un script refusé n'ouvre même pas de connexion ; un énoncé inconnu signale à l'appelant qu'une décision humaine est requise. Une liste redact complémentaire permet d'autoriser une requête tout en caviardant sa vue (SQL et résultats jamais affichés ni journalisés). Chaque exécution (y compris les refus) est journalisée dans une session.

Spécifications complètes : doc/spec/** (A01 portée, E01 CLI, E02 bases, E03 politique, E04 exécution, E05 sessions).


Utilisation

sql-client exec --database <nom> (--sql <texte> | --sql-file <chemin> | --sql-stdin)
                [--timeout <sec>] [--max-rows <n>] [--json] [--once] [--transaction]
sql-client policy check <base> <type> <objet>
sql-client policy check <base> --sql <texte>
sql-client policy allow  <base> <types> <motif-objet>
sql-client policy deny   <base> <types> <motif-objet>
sql-client policy redact <base> <types> <motif-objet> [--mask <champ>[:<regex>]]…
sql-client policy remove <base> <types> <motif-objet>
sql-client policy list [--json]
sql-client database add <nom> --provider <sqlserver|mysql|postgresql>
                        --host <fqdn|ip> [--port <n>] --dbname <base>
                        --user <utilisateur> --password-stdin
                        [--no-encrypt] [--trust-server-certificate]
sql-client database remove <nom>
sql-client database list [--json]
sql-client database test <nom>
sql-client session start [<id>]
sql-client session end [<id>]
sql-client session current [--json]
sql-client session list [--json]
sql-client --version | --readme | --help

Option globale : --config-dir <chemin> (sinon SQLCLIENT_HOME, sinon ./.sql-client — local au projet, créé au besoin ; en lecture seule, repli sur les fichiers livrés à côté du binaire ; les journaux — sessions et debug — vont dans .log/sql-client/ du répertoire de travail). --session <id> cible une session précise (créée si absente). --no-sessions désactive l'inscription locale des sessions (équivaut à SQLCLIENT_NO_SESSIONS=1).


Bases de données

Les bases cibles sont déclarées par nom dans config.json : fournisseur, hôte, port, base et options TLS. Les secrets (mot de passe) sont stockés à part dans credentials.json (durci), jamais dans config.json, et se fournissent sur l'entrée standard.

# SQL Server
printf '%s' 'le-mot-de-passe' | sql-client database add appdb --provider sqlserver --host db01.example.com --dbname app --user agent --password-stdin

# MySQL (TLS sans validation du certificat)
printf '%s' 'le-mot-de-passe' | sql-client database add inventaire --provider mysql --host mysql.interne.local --dbname inventaire --user bot --password-stdin --trust-server-certificate

# PostgreSQL (sans TLS, réseau interne)
printf '%s' 'le-mot-de-passe' | sql-client database add telemetrie --provider postgresql --host 10.0.0.12 --dbname telemetrie --user agent --password-stdin --no-encrypt

sql-client database test appdb     # connexion réelle, sonde SELECT 1, version du serveur
sql-client database list

Seule l'authentification utilisateur + mot de passe est supportée (auth intégrée Windows / Kerberos / Azure AD hors portée). Ports par défaut : 1433 (sqlserver), 3306 (mysql), 5432 (postgresql).


Politique d'autorisation (allow / deny / redact)

Une règle est la combinaison de trois éléments — le modèle de restapi-client, où le type d'énoncé remplace la méthode REST :

  1. base — nom de la base déclarée (* accepté) ;
  2. types — SELECT, liste SELECT,UPDATE, ou * (EXEC, EXECUTE et CALL sont normalisés en EXEC) ;
  3. motif d'objet — glob simple sur le nom d'objet (* seul métacaractère), insensible à la casse, comparé à chaque table/vue/procédure référencée par l'énoncé (jointures comprises).
sql-client policy check appdb SELECT users                  # décision sans exécuter
sql-client policy check appdb --sql "SELECT * FROM users u JOIN commandes c ON c.userId = u.id"
sql-client policy allow appdb SELECT "users*"               # autoriser
sql-client policy allow appdb SELECT,UPDATE "commandes"
sql-client policy deny  "*"   DROP,TRUNCATE "*"             # interdire le DDL destructeur partout
sql-client policy redact vault "*" "secrets*"               # cacher tout l'appel
sql-client policy redact appdb SELECT "jetons_api" --mask "column-jeton"
sql-client policy list
  • Un script de plusieurs énoncés est évalué énoncé par énoncé, chaque énoncé sur chacun de ses objets ; le pire cas gagne (deny > unknown > allow) et rien n'est envoyé tant que tout n'est pas autorisé — aucune exécution partielle.
  • La liste deny est prioritaire ; le défaut est fermé : un énoncé non couvert n'est jamais envoyé silencieusement (code 253, décision humaine requise). L'analyse échoue fermé elle aussi (énoncé sans objet reconnu → seul un motif * le couvre).
  • La liste redact est indépendante : elle ne rend pas un énoncé autorisé — elle caviarde ce que l'appel expose, à la fois dans la sortie et dans le journal de session :
    • sans --mask : tout l'appel est caché (texte SQL, colonnes et lignes → [REDACTED] ; seuls base, analyse, nombres de lignes et durée restent visibles) ;
    • avec --mask <champ>[:<regex>] (répétable) : seuls les champs désignés sont masqués — champ entier sans regex, ou uniquement les parties correspondant à la regex (valeurs texte). Champs : sql (texte du script), rows (toutes les valeurs), column-<nom> (une colonne des résultats, ex. column-mot_de_passe).
  • Masquage automatique en plus de la politique : toute occurrence littérale du mot de passe de la base (dans le SQL ou les résultats) est toujours remplacée par [REDACTED] dans la sortie et le journal.
code Signification
0 Script exécuté sans erreur SQL.
1 Erreur SQL rapportée par le serveur (syntaxe, contrainte, privilège) ; détail via --json (error) et le diagnostic stderr.
250 Erreur de configuration (base inconnue, identifiants absents).
251 Délai dépassé (défaut 30 s, --timeout 0 = illimité).
252 Erreur d'usage (arguments invalides, script vide).
253 Énoncé inconnu — autorisation utilisateur requise (rien envoyé).
254 Refusé par une règle deny (rien envoyé).
255 Erreur de connexion (réseau, authentification, TLS).

L'ajout d'une règle allow, deny ou redact est une décision explicite de l'utilisateur : présenter l'énoncé inconnu, recueillir la décision, puis seulement policy allow / policy deny (ou exec --once pour une autorisation ponctuelle).

Face à un code 253, les quatre décisions possibles de l'utilisateur :

Décision Action de l'agent
Autoriser toujours policy allow <base> <type> "<motif>" (une règle par énoncé approuvé) puis relancer exec.
Autoriser une seule fois Relancer exec avec --once ; aucune persistance.
Refuser toujours policy deny <base> <type> "<motif>" ; ne pas exécuter.
Refuser cette fois-ci Ne rien persister, ne pas exécuter.

Ne jamais généraliser un motif au-delà de ce que l'utilisateur a approuvé ; ne jamais proposer de motif large pour un type mutatif (INSERT, UPDATE, DELETE, MERGE, DDL, EXEC).


Exécution

sql-client exec --database appdb --sql "SELECT TOP 10 * FROM users ORDER BY createdAt DESC"
sql-client exec --database appdb --sql-file ./scripts/maj-stocks.sql
sql-client exec --database appdb --sql-file ./scripts/procedures.sql --transaction
cat requete.sql | sql-client exec --database telemetrie --sql-stdin --json
  • Chaque opération SQL est autorisée séparément (jamais « ligne par ligne ») ; une définition CREATE PROCEDURE/FUNCTION/TRIGGER compte comme une seule opération sur le nom de la routine.
  • Le script est découpé en lots selon le fournisseur (lignes GO pour SQL Server, directive DELIMITER pour MySQL) puis envoyé, dans l'ordre, sur une même connexion ; un script sans séparateur part en une seule commande, tel quel (variables, tables temporaires et transactions explicites conservent leur sémantique).
  • --transaction enveloppe le script dans une transaction client unique (commit au succès, rollback à la première erreur ou au délai dépassé) ; sinon le script gère sa propre transaction ou l'autocommit s'applique.
  • Chaque jeu de résultats est plafonné à --max-rows lignes (1000 par défaut, 0 = illimité) ; au-delà, le jeu est marqué truncated.
  • En mode texte, les lignes de chaque jeu sont écrites sur stdout en JSON (tableau d'objets colonne: valeur) ; le résumé (énoncés, jeux, lignes, durée) est un diagnostic stderr (préfixé sql-client:).
  • --json produit un unique objet structuré sur stdout : base, fournisseur, décision, règle, analyse des énoncés (statements), resultSets, rowsAffected, error, redacted, durationMs, timedOut, transaction, rolledBack.
  • Valeurs : NULL → null, nombres/booléens natifs, dates ISO 8601, binaires en Base64.

Sessions

Une session regroupe les exec d'une période de travail et journalise intégralement chaque exécution (y compris refusée et la sonde de database test) dans .log/sql-client/sessions/<id>.jsonl (dans le répertoire de travail) : analyse des énoncés, décision, texte SQL et résultats (plafonnés à 64 KiB chacun), lignes affectées, erreur, durée. Les valeurs journalisées sont la vue caviardée : une donnée masquée (règle redact ou secret) n'est jamais persistée.

En complément, chaque script réellement envoyé est tracé dans un journal de debug SQL quotidien, sql-debug-AAAA-MM-JJ.log (dans .log/sql-client/ du répertoire de travail) : même vue caviardée, mais résultats intégraux (non plafonnés). Ce journal n'est pas affecté par --no-sessions.

sql-client session start maintenance-1
sql-client session current
sql-client session end maintenance-1

La session active est la dernière session non terminée et non expirée (expiration : 10 min d'inactivité par défaut). Sans session active, un exec en crée une automatiquement.


Sécurité

  • Deny prioritaire et défaut fermé : un énoncé non couvert n'est jamais envoyé silencieusement — l'analyse échoue fermé, et un script partiellement couvert n'est pas envoyé du tout.
  • Secrets isolés dans credentials.json (permissions propriétaire seul sous POSIX), jamais affichés ni journalisés — toute occurrence littérale du mot de passe est automatiquement remplacée par [REDACTED].
  • Caviardage : les données sensibles (liste redact, masques par champ et regex) ne transitent ni par la sortie de l'agent ni par les journaux.
  • Journalisation intégrale de chaque exécution (décision, analyse, SQL, résultats) dans la session.
  • Moindre privilège côté serveur : le compte SQL déclaré ne devrait détenir que les privilèges nécessaires — la politique est un garde-fou, pas une barrière.

Le modèle est coopératif : sql-client structure et trace les requêtes d'un agent ; il se combine à l'allowlist du harnais (n'autoriser que sql-client, jamais un client SQL brut, ni l'édition directe des fichiers de politique et d'identifiants).

No packages depend on claria.tools.sql-client.

Build 1.0.0.20260819.1 du 2026-08-20 03:29:31 UTC - pipeline skill tools - sql-client run 2120 - commit c459994b8934484f497073c13eb1e289a1d66b28

This package has no dependencies.

Version Downloads Last updated
1.0.0-build.20260819.1 8 08/20/2026