
safer-dependencies v0.6.0
Couche de sécurité automatisée des dépendances pour les assistants de codage IA qui audite les packages pour les CVEs, les typosquats, l'abandon, les problèmes d'âge de version et l'intégrité des hachages dans les écosystèmes npm, PyPI, RubyGems, Maven, Go et Rust.
Des dépendances plus sûres pour Claude Code
Lorsque les assistants de codage IA comme Claude ajoutent des packages à votre projet, ils choisissent souvent la version qui semble la plus appropriée — sans vérifier si elle présente des vulnérabilités de sécurité connues, si le package est toujours activement maintenu, ou si le nom est à une faute de frappe près d'un sosie malveillant.
safer-dependencies est une couche de sécurité pour Claude Code : elle se place entre Claude et vos fichiers de manifeste et exécute automatiquement ses contrôles de sécurité : les installations vulnérables sont refusées avant même de s'exécuter, et une version risquée écrite dans un manifeste est corrigée sur le disque juste après l'écriture. Elle détecte et corrige les dépendances risquées — CVE, typosquats, packages abandonnés et problèmes d'ancienneté de version, plus une période de refroidissement pour les nouvelles versions — pour npm, PyPI, RubyGems, Maven, Go, Rust et PHP (Composer). Consultez CAPABILITIES.md pour savoir exactement ce qui est couvert et ce qui ne l'est pas.
Nouveau ici ? GETTING-STARTED.md vous fait passer de zéro à une installation fonctionnelle en environ cinq minutes.
Sécurité et confidentialité : voir SECURITY.md (divulgation des vulnérabilités), PRIVACY.md (sortie de données, aucune télémétrie) et CAPABILITIES.md (ce contre quoi l'outil vous défend et ce qu'il ne couvre pas).
Licence (source disponible — PAS « open source » selon l'OSI) : libre d'utilisation et de modification pour vos propres besoins, y compris l'utilisation interne à but lucratif/en entreprise et la création de produits que vous vendez. Une licence payante distincte est requise uniquement pour monétiser le logiciel lui-même — le vendre, l'inclure dans un produit ou un service vendu, ou proposer ses fonctionnalités à des tiers moyennant des frais (y compris hébergé/SaaS/API). La redistribution et les dérivés doivent conserver la licence et créditer ce projet. Voir LICENSE (section 4 pour la restriction commerciale) ; demandes de licence commerciale via github.com/robert-auger.
Sommaire
- Premiers pas — de zéro à installé en environ cinq minutes
- Ce qu'il fait
- Comment ça marche
- Ce qui le déclenche
- Ce que contient ce dépôt
- Écosystèmes pris en charge
- Installation
- Niveaux d'avertissement
- Journal d'audit
- Prérequis
- FAQ
Premiers pas
GETTING-STARTED.md vous fait passer de zéro à une installation fonctionnelle en environ cinq minutes — prérequis, installation interactive et vérification. Pour la référence complète d'installation (installations globale/projet/manuelle, spécificités Windows, la liste blanche des permissions, mise à jour et désinstallation), voir INSTALLATION.md.
Utilisation quotidienne : une fois les hooks installés, il n'y a rien à exécuter — safer-dependencies fonctionne automatiquement en arrière-plan. Lorsque Claude ajoute ou installe des packages, il signale les dépendances risquées et met à niveau les versions vulnérables vers une version sûre sur place — et bloque une installation connue comme vulnérable avant même qu'elle ne s'exécute — afin que les packages dangereux soient détectés et corrigés sans que vous ayez à le demander. Vous pouvez toujours l'invoquer directement à tout moment : "est-ce que [email protected] est sûr ?", "vérifier la configuration de safer-dependencies", ou "afficher les statistiques de safer-dependencies".
Ce qu'il fait
Lorsque Claude s'apprête à ajouter un package à votre projet, safer-dependencies intercepte l'action et exécute 5 contrôles :
- Provenance -- registre officiel, détection de typosquat (npm/PyPI/RubyGems/Maven/crates.io), ancienneté du package
- Ancienneté de la version -- choisit la version stable la plus récente publiée il y a plus de 7 jours (période de refroidissement)
- Analyse des vulnérabilités -- API OSV, avec les outils natifs de l'écosystème (npm audit, pip-audit, bundle audit) lorsqu'ils sont disponibles
- Intégrité de l'épinglage de hachage -- pour les lignes PyPI
requirements.txtavec des épingles--hash=sha256:..., le hachage déclaré est validé par rapport aux hachages publiés par PyPI ; une discordance émet un WARNING - Packages abandonnés et obsolètes -- les packages connus comme abandonnés (par exemple
paperclip,request,pycrypto,github.com/dgrijalva/jwt-go) sont immédiatement bloqués de manière stricte avec un remplacement suggéré ; les packages sans publication stable depuis plus de 2 ans reçoivent un avertissementSTALE:de nature consultative. Les packages bloqués de manière stricte sont retirés du manifeste et Claude demandera comment procéder ; les packages uniquement obsolètes sont laissés en place.
Si des problèmes sont détectés, Claude émet des avertissements et peut revenir à une version plus sûre. Tous les contrôles sont consignés dans ~/.claude/safer-dependencies-audit-YYYY-MM.log (un fichier par mois civil).
Comment ça fonctionne
La compétence fonctionne selon cinq modes (résumés ci-dessous ; la justification de conception la plus approfondie se trouve dans skills/safer-dependencies.md) :
Mode normal (manuel)
Lorsque Claude s'apprête à écrire un import, à ajouter un package à un manifeste ou à mettre à jour un fichier de verrouillage, la compétence s'exécute directement dans votre session :
- Interroge le registre de packages pour les versions stables
- Sélectionne automatiquement la version la plus récente publiée il y a plus de 7 jours (déterministe, sans jugement du LLM)
- Vérifie les vulnérabilités connues via les outils de l'écosystème et l'API OSV
- Vérifie les signatures de packages lorsqu'elles sont disponibles
- Émet des avertissements si des problèmes sont détectés, épingle la version exacte
- Consigne le résultat dans la piste d'audit
La sélection de version est gérée par des scripts Python autonomes fournis avec la compétence, et non par le LLM qui interprète des règles. La commande affiche SELECTED: <version> et Claude utilise exactement cette version.
Mode interception (automatique)
Configurez .claude/settings.json avec un hook PostToolUse pour activer la vérification automatique et transparente des packages :
- Claude écrit un fichier manifeste (par exemple
package.json) avec la version initialement demandée — le fichier est écrit sur le disque - Le hook
PostToolUsese déclenche immédiatement après la fin de l'écriture et appellesafer-dependencies-shim.sh - Le shim lit le fichier, analyse les packages déclarés et exécute tous les contrôles de sécurité (typosquat, abandon, CVE, obsolescence, épinglage de hachage)
- Si des corrections sont nécessaires, le shim réécrit le manifeste en place avec des versions sûres (ou supprime les entrées qui n'ont pas de version sûre)
- Le shim émet des signaux (
UPDATED:,BLOCKED:,WARNING:,STALE:,MAJOR-UPDATE-CONFIRM:,REFACTOR-REQUIRED:,REGRESSION:,TYPOSQUAT-CONFIRM:,VERIFY:,CLEAN:) viahookSpecificOutput.additionalContextsur stdout.REGRESSION:précède unMAJOR-UPDATE-CONFIRM:lorsque le journal d'audit montre que la même paire (fichier, package) a déjà été corrigée précédemment vers la même cible sûre — c'est-à-dire qu'un sous-agent ou un plan obsolète a réintroduit une version connue comme vulnérable, et l'orchestrateur doit restaurer la version précédemment approuvée plutôt que de re-décider de la mise à niveau majeure. - Claude reçoit ces signaux sous forme de rappel système et effectue le travail de suivi (trouver les imports affectés, exécuter les tests, refactoriser pour les changements cassants)
Note de conception — Forme C (correctif après écriture) : le hook ne bloque PAS les écritures. Chaque version vulnérable est d'abord écrite sur le disque, puis automatiquement corrigée dans le même cycle d'utilisation de l'outil. Ce choix est délibéré par rapport à une conception bloquante via PreToolUse — voir FAQ.md pour les compromis.
Exemple de signal :``` UPDATED: aiohttp 3.8.5 → 3.9.0 (HIGH: 33 CVEs fixed)
L'agent parent utilise ces signaux pour identifier le code affecté et le refactoriser si nécessaire.
### Mode pré-installation (hook Bash)
Configurez `.claude/settings.json` avec un hook `PreToolUse:Bash` pour activer l'audit préalable des commandes d'installation du gestionnaire de paquets. Cela complète (ne remplace pas) le mode Intercept — ensemble, ils forment une défense en couches.
1. Claude tente un appel d'outil Bash (p. ex. `npm install [email protected]`)
2. Le hook `PreToolUse` se déclenche avant que l'appel ne s'exécute et invoque `safer-dependencies-pretooluse-bash.sh`
3. Un filtre préliminaire en bash pur court-circuite les commandes non-PM en ~115 ms (sans invocation Python), donc `git status` / `ls` / `npm test` ont un coût négligeable sur le chemin chaud
4. Pour les installations reconnues de gestionnaire de paquets (`npm`/`pnpm`/`yarn` `install`/`i`/`add`), l'assistant tokenise via `shlex`, extrait chaque argument `pkg@version`, et les soumet à OSV
5. Tout épinglage concret vulnérable → le hook retourne `permissionDecision: "deny"` avec un GHSA-id + CVSS + résumé par résultat, plus une suggestion d'invoquer la compétence safer-dependencies
6. L'installation ne s'exécute jamais — aucun téléchargement réseau, aucun script postinstall
**Pourquoi cela existe en plus du mode Intercept :** le shim post-écriture est aveugle à Bash. `npm install [email protected]` s'exécute jusqu'au bout (et les scripts postinstall s'exécutent) avant qu'aucun audit ne se déclenche ; `npm install -g typosquat-pkg` n'écrit aucun manifeste de projet. Le mode pré-installation comble structurellement ces lacunes.
Le mode pré-installation ne voit que ce que l'utilisateur a **saisi** (arguments `pkg@version` sur la ligne de commande). Il ne peut pas voir l'arbre de dépendances transitif que le résolveur installera réellement. Le **mode post-installation** (ci-dessous) audite le lockfile une fois l'installation terminée — les deux modes sont complémentaires, pas redondants.
**Portée :** les CLI de gestionnaires de paquets traitées ici couvrent cinq écosystèmes (npm/pnpm/yarn/bun/npx/deno, pip/pip3/pipx/pipenv/uv/uvx/poetry, gem/bundle, go, cargo), plus Maven via le mode Intercept (les dépendances Maven sont généralement déclarées dans `pom.xml`/`build.gradle`, pas ajoutées via un verbe CLI).
> **Lacune connue :** l'outil CLI Maven prend en charge les téléchargements directs via `mvn dependency:get -Dartifact=group:art:version` et `mvn dependency:copy`. Ce hook ne reconnaît pas encore ces invocations. Si vous les utilisez régulièrement, le shim post-écriture existant capture toujours ce qui atterrit dans votre manifeste, mais la protection avant téléchargement ne s'applique qu'aux écosystèmes listés ci-dessus. Consigné comme suivi ultérieur.
Syntaxe reconnue par écosystème :
| PM | Verbes | Syntaxe d'épinglage exact |
|---|---|---|
| `npm`, `pnpm`, `yarn`, `bun` | `install`, `i`, `add` (plus `yarn`/`pnpm dlx`, `bun x`, `yarn create`) | `[email protected]`, `@scope/[email protected]` |
| `npx` | (sans verbe — le paquet est en première position) | `[email protected]` |
| `deno` | `add`, `install` | `npm:[email protected]` (spécifications préfixées npm) |
| `pip`, `pip3`, `pipx`, `pipenv`, `uv`, `uvx`, `poetry` | `install` (pip/pip3/pipx/pipenv) / `add` (uv/poetry) / sans verbe (uvx) | `pkg==1.2.3` (les extras `pkg[extra]==X` sont également gérés) |
| `gem`, `bundle` | `install` (gem) / `add` | `-v 1.2.3`, `--version 1.2.3`, `--version=1.2.3` (option séparée) |
| `go` | `get`, `install` | `[email protected]` (doit inclure le préfixe `v` conformément aux modules Go) |
| `cargo` | `add`, `install` | `[email protected]` |
Les épinglages par plage (npm `^4.17`, pip `>=`, poetry `^`/`~`, Go `@latest`) et les versions non spécifiées passent au mode Intercept après l'installation — le shim post-écriture audite ce que le résolveur choisit. La réécriture automatique vers une version sûre est prévue comme suivi ultérieur.
**Mode d'échec :** fail-open. Toute erreur (Python absent, incident réseau, entrée malformée) se termine par 0 sans sortie, permettant à bash de continuer. Le mode Intercept s'exécute toujours après l'installation, donc un échec de l'audit préalable se dégrade proprement vers la protection existante.
**Exemple de refus :**```
safer-dependencies pre-flight audit blocked this install.
Vulnerable pinned version(s) detected:
- [email protected] → GHSA-35jh-r3h4-6jhm (CVSS:7.4): Command Injection in lodash
Re-run with a patched version, or invoke the safer-dependencies skill
for a recommended pin.
Mode post-installation (hook Bash)
Configurez .claude/settings.json avec un hook PostToolUse:Bash pour activer
l'audit post-vol après les commandes Bash. Il exécute trois analyses indépendantes
sur le cwd de la commande, chacune comblant une lacune que les autres hooks ne peuvent pas traiter :
- Analyse A — fichiers de verrouillage. Après un verbe d'installation réussi (
npm install,bundle install,poetry install,uv sync,go mod tidy, etc.), audite les fichiers de verrouillage fraîchement modifiés (package-lock.json,Gemfile.lock,poetry.lock,uv.lock,go.sum,yarn.lock,pnpm-lock.yaml,Pipfile.lock). Cela comble la lacune des CVE transitives que Pre-Install ne peut pas voir : l'utilisateur a saisipkg@version, mais le résolveur a pu tirer des dizaines de dépendances transitives que personne n'a nommées. - Analyse B — manifestes. Après toute commande Bash non sur une
liste de blocage en lecture seule (
ls,cat,git status, …), audite les manifestes fraîchement modifiés. C'est le seul recours pour les modifications de manifestes effectuées viased -i,jq, ou un script — celles-ci contournent l'outilWrite/Editsur lequel le mode Intercept se greffe. - Analyse C — environnement résolu. Un simple
pip install/pip install -r requirements.txtn'écrit aucun fichier de verrouillage, donc l'analyse A ne voit jamais l'arbre résolu. Après une installation de type pip, l'analyse C ré-invoque le même pip avec unlist --format=jsonen lecture seule et vérifie via OSV l'intégralité de l'environnement résolu (direct + transitif).
Comment une analyse s'exécute :
- Claude exécute un appel d'outil Bash
- Le hook
PostToolUsese déclenche après la fin de la commande et invoquesafer-dependencies-posttooluse-bash.sh - Un filtre précoce en bash pur court-circuite les commandes qui ne correspondent à aucune porte d'analyse en
~115 ms (même convention de chemin rapide que Pre-Install), donc
ls/git/catcoûtent négligeablement - Chaque analyse parcourt
cwdavecfind -maxdepth 5(couvre les layouts monorepo ; exclutnode_modules,.git,.venv,venv) pour les fichiers modifiés au cours des 60 dernières secondes — à remplacer viaSAFE_DEP_POSTINSTALL_MTIME_WINDOW - Pour chaque fichier fraîchement modifié (analyse A/B), le hook forge une charge utile
synthétique
PostToolUse:Writeet la transmet au shim existant — les auditeurs de fichiers de verrouillage et de manifestes du shim s'exécutent tels quels, sans logique dupliquée - Les signaux par fichier sont concaténés et émis sous forme d'un seul JSON
hookSpecificOutputvers l'agent parent
Ce qu'il détecte que Pre-Install ne détecte pas : les vulnérabilités transitives.
Un bundle install d'apparence propre peut tirer [email protected] (CVE-2025-27610)
en tant que dépendance transitive de sinatra — l'utilisateur n'a jamais saisi rack, donc
Pre-Install ne peut pas le voir, mais Post-Install lit le
Gemfile.lock résolu et signale la CVE.
Portée : l'analyse A ne réécrit pas les versions résolues — le contrat d'auto-correction
ne s'applique qu'aux manifestes que Claude a écrits directement. Pour les CVE transitives,
le correctif consiste généralement à « mettre à jour la dépendance directe qui possède la transitive, » ce qui
nécessite un jugement humain. L'analyse B, elle, fait de l'auto-correction, car elle audite les manifestes
via le même chemin de shim que le mode Intercept. L'analyse A est ignorée lorsque le
niveau de vérification transitive est défini sur off (config set checks.transitive off).
Mode de défaillance : fail-open, comme les autres hooks. Toute erreur (shim manquant, charge utile malformée, Python indisponible) se termine par 0 en silence.
Exemple d'AVERTISSEMENT :``` WARNING: [email protected] in lock file has GHSA-29mw-wpgm-hmr9, GHSA-35jh-r3h4-6jhm
### Mode Post-Agent (Paire de hooks Agent)
Les quatre modes ci-dessus ne se déclenchent que pour les appels d'outils de la **session racine**. Lorsque la session racine délègue à un sous-agent (via l'outil `Agent` — de nombreuses compétences et commandes slash font cela en interne), les appels Write/Edit/Bash du sous-agent contournent tous ces modes. Le mode Post-Agent est le filet de sécurité réactif pour cette lacune.
1. Un hook `PreToolUse:Agent` (`safer-dependencies-pretooluse-agent.sh`) s'exécute immédiatement avant chaque envoi d'Agent et touche un fichier sentinelle à `/tmp/.safer-deps-agent-<PPID>-<session_id>.sentinel` (en repli sur un nom basé uniquement sur le PPID lorsqu'aucun identifiant de session n'est disponible)
2. Le sous-agent s'exécute et peut écrire des manifests ou des lockfiles
3. Un hook `PostToolUse:Agent` (`safer-dependencies-posttooluse-agent.sh`) s'exécute après le retour de l'appel Agent, effectue un `find` sur chaque manifest et lockfile plus récent que la sentinelle, et audite chacun via le même chemin shim
4. Les résultats remontent comme `additionalContext` au tour suivant de la session racine ; la sentinelle est supprimée
Les sous-agents imbriqués sont couverts automatiquement — le `PostToolUse:Agent` de la racine ne se déclenche qu'après que tout le travail de l'agent externe (y compris tout ce qu'*il* a délégué) est sur disque. La seule lacune est une installation globale qui n'écrit ni manifest ni lockfile (`npm install -g …`) : il n'y a rien à analyser. Comme les autres hooks, il échoue ouvert — toute erreur (sentinelle manquante, shim manquant, payload illisible) se termine par 0 en silence. La justification complète de la conception se trouve dans `skills/safer-dependencies.md`.
## Ce qui le déclenche
La compétence se déclenche automatiquement lorsque Claude :
**Opérations de manifest / d'installation**
- Ajoute ou met à jour un paquet dans `package.json`, `requirements.txt`, `Gemfile`, `pom.xml`, `build.gradle`, `Cargo.toml`, `go.mod`, ou tout autre manifest pris en charge
- Écrit un `import`, `require` ou `use` pour un paquet pas encore déclaré dans le manifest
- Génère ou met à jour un lockfile (ne vérifie que les entrées nouvelles/modifiées)
- Exécute une installation via un gestionnaire de paquets dans Bash (`npm install`, `bundle install`, `poetry install`, `uv sync`, `go mod tidy`, etc.) — Pre-Install audite les arguments de la commande, Post-Install audite le lockfile résultant
- Écrit un `Dockerfile` ou un workflow CI (`.github/workflows/*.yml`, etc.) qui intègre des étapes d'installation épinglées de gestionnaire de paquets
**Questions de sélection et de recommandation**
- Comparaisons de bibliothèques/frameworks : "devrais-je utiliser axios ou node-fetch ?", "moment vs dayjs ?", "lequel est meilleur, X ou Y ?"
- Demandes de recommandation : "quel est un bon client HTTP pour Python ?", "recommande une bibliothèque de journalisation pour Go", "quel paquet gère le CSV dans Node ?"
- Sélection de version : "quelle version de Django devrais-je utiliser ?", "dernier Flask stable ?"
**Expressions d'intention d'utilisation (pré-ajout)**
- "Je veux utiliser FastAPI pour ça", "je pense ajouter Celery", "nous envisageons Prisma comme ORM", "utilisons Tailwind"
**Questions sur la santé et la fiabilité des paquets**
- "moment.js est-il toujours maintenu ?", "ce gem est-il toujours actif ?", "X est-il abandonné ?", "X est-il en fin de vie (EOL) ?", "puis-je faire confiance à ce paquet ?", "quand faker a-t-il été mis à jour pour la dernière fois ?"
**Commandes de génération de squelette**
- `npx create-react-app`, `npm create vite@latest`, `django-admin startproject`, `rails new`, `cargo new` + `cargo add`, "démarrer un nouveau projet FastAPI"
**Ajouts implicites de paquets (demandes de fonctionnalités impliquant une nouvelle dépendance)**
- "Ajouter le cache Redis à l'application", "se connecter à Postgres", "ajouter l'authentification JWT", "écrire du code pour envoyer des e-mails" — se déclenche lorsqu'aucun paquet pour cette fonctionnalité n'est déjà dans le manifest
**Migration et portage**
- "Migrer de requests vers httpx", "passer de CRA à Vite", "porter de moment vers date-fns" — audite le paquet entrant
La compétence ne se déclenche **pas** pour :
- Les imports de la bibliothèque standard (`os`, `fs`, `java.util.*`, etc.)
- Les dépendances déjà déclarées qui ne sont pas modifiées
- La discussion académique sur le fonctionnement interne d'un paquet ("explique le reconciler de React", "comment fonctionne la résolution de modules de webpack ?") — les questions de comparaison et de sélection se déclenchent toujours
- L'installation d'applications au niveau OS, de runtimes ou d'extensions IDE (Python lui-même, Docker, Homebrew, extensions VS Code)
## Contenu de ce dépôt
Il s'agit d'un **ensemble compétence + hooks**, pas d'un fichier de compétence unique. Une installation complète déploie ces éléments :
| Fichier | Rôle |
|---|---|
| `skills/safer-dependencies.md` | La **compétence** (`SKILL.md` une fois installée). Décrit les procédures d'audit et inclut un mode de gestion pour l'installation/les statistiques. |
| `skills/safer-dependencies-shim.sh` | Hook `PostToolUse:Write`/`Edit` — audite les écritures de manifest + lockfile et corrige automatiquement les versions vulnérables en place (mode Intercept). |
| `skills/safer-dependencies-pretooluse-bash.sh` | Hook `PreToolUse:Bash` — audit OSV pré-exécution des commandes d'installation du gestionnaire de paquets ; refuse les épinglages concrets vulnérables avant que l'installation ne s'exécute (mode Pre-Install). |
| `skills/safer-dependencies-posttooluse-bash.sh` | Hook `PostToolUse:Bash` — audit post-exécution après les commandes Bash ; détecte les CVE transitives dans les lockfiles fraîchement écrits, les manifests édités via `sed`/`jq`/scripts, et l'environnement résolu d'un simple `pip install` (mode Post-Install). |
| `skills/safer-dependencies-pretooluse-agent.sh` + `skills/safer-dependencies-posttooluse-agent.sh` | Paire de hooks `PreToolUse:Agent` + `PostToolUse:Agent` — comble la lacune de couverture des sous-agents. Les modes 2 à 4 ne se déclenchent que pour les appels d'outils de la session racine, donc tout manifest écrit par un sous-agent les contourne. Post-Agent audite ce que le sous-agent a écrit après chaque retour d'appel d'outil Agent (mode Post-Agent). |
| `skills/scripts/` | Bibliothèque Python partagée (`safedep/`) et scripts de résolution autonomes utilisés par tous les hooks. |
| `skills/scripts/safer_dependencies_manager.py` | Module de gestion pour l'installation interactive, les statistiques d'utilisation et la validation de la configuration. |
Le fichier de compétence seul ne suffit pas — sans hooks, l'invocation automatique dépend de la décision de Claude d'utiliser la compétence. Installez les cinq éléments pour une couverture complète ; de nombreuses compétences et commandes slash délèguent des sous-agents en interne, donc la paire Post-Agent compte même si vous n'en lancez jamais explicitement. (Voir [FAQ.md](https://github.com/robert-auger/safer-dependencies/blob/HEAD/FAQ.md#why-a-skill-alone-is-not-sufficient) pour comprendre pourquoi une compétence seule ne peut pas garantir la couverture.)
## Écosystèmes pris en charge
| Écosystème | Manifest | Lockfile |
|-----------|----------|-----------|
| npm | `package.json` | `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` |
| PyPI | `requirements.txt`, `pyproject.toml`, `Pipfile`, `setup.py`, `setup.cfg` | `Pipfile.lock`, `poetry.lock`, `uv.lock` |
| RubyGems | `Gemfile`, `*.gemspec` | `Gemfile.lock` |
| Maven | `pom.xml`, `build.gradle`, `libs.versions.toml` | -- |
| Go | `go.mod` | `go.sum` |
| Rust | `Cargo.toml` | `Cargo.lock` |
| PHP (Composer) | `composer.json` | `composer.lock` |
## Installation
Nouveau sur le projet ? Commencez par **[GETTING-STARTED.md](https://github.com/robert-auger/safer-dependencies/blob/HEAD/GETTING-STARTED.md)**. La version courte :```bash
git clone https://github.com/robert-auger/safer-dependencies /tmp/safer-dependencies
python3 /tmp/safer-dependencies/skills/scripts/safer_dependencies_manager.py interactive_install
L'installateur demande la portée (globale ou projet) et les hooks à activer, puis écrit settings.json pour vous — à la fois les entrées de hook et la liste d'autorisations qui permet aux commandes de vérification de la compétence de s'exécuter sans invite d'approbation à chaque audit.
Tout le reste lié à l'installation se trouve dans INSTALLATION.md, la référence unique pour les mécanismes d'installation : installations manuelles fichier par fichier (globales et au niveau projet), spécificités Windows, hooks Post-Agent, la liste d'autorisations, la vérification de l'installation, la mise à jour, l'épinglage à un tag de release et la désinstallation.
Après l'installation, la gestion au quotidien se fait en langage naturel via Claude — install safer-dependencies (relancer / modifier les hooks), show safer-dependencies stats, check safer-dependencies setup — ou le menu /safer-dependencies. La mise à jour s'effectue également en session : /safer-dependencies update applique la dernière release (update --check pour un dry-run, update --rollback pour annuler) ; voir INSTALLATION.md pour le modèle de confiance.
Remarque sur les plateformes : macOS, Linux et Windows sont pris en charge. Windows nécessite Git for Windows (qui fournit bash) et Python 3 dans le
PATH— pas besoin de WSL. Les tests pratiques effectués à ce jour se sont concentrés sur macOS et Windows ; la prise en charge de Linux est validée par la matrice CI automatisée.
Configuration
Deux éléments sont configurables après l'installation :
- Liste d'autorisations — préapprouve les commandes de vérification en lecture seule de la compétence (les règles
npm audit/bundle auditsous leur forme exacte et les scripts de résolution de la compétence) afin que les audits s'exécutent sans invite d'approbation à chaque fois ;curln'est jamais préapprouvé, etnpm view/pip-auditsont en opt-in via le profil Convenience. L'installateur interactif écrit les entrées de base pour vous ; les installations manuelles ajoutent le bloc complet à la main. Bloc complet et justifications : INSTALLATION.md → Liste d'autorisations. - Politique de sécurité — la fenêtre/mode de cooldown en fonction de l'âge de la release et un niveau
off/warn/blockpar vérification pour chaque type de vérification, modifiée via/safer-dependencies configet stockée dans~/.config/safer-dependencies/config.toml. Schéma et sémantique des niveaux :skills/references/configuration.md.
Niveaux d'avertissement
| Niveau | Signification | Exemple |
|---|---|---|
| CRITICAL | Arrêter et demander à l'utilisateur | Typosquat détecté, signature falsifiée |
| HIGH | Avertir et continuer | CVE connue, package de moins de 30 jours |
| MEDIUM | Avertir et continuer | Version de moins de 7 jours, signature manquante |
| LOW | Avertir et continuer | Gem Ruby non signée (cas attendu) |
Journal d'audit
Chaque vérification est consignée dans ~/.claude/safer-dependencies-audit-YYYY-MM.log (un fichier par mois calendaire, où YYYY-MM est l'année-mois UTC) sous la forme d'une seule ligne JSON. La variable d'environnement SAFE_DEP_AUDIT_LOG permet de remplacer le chemin complet (lorsqu'elle est définie, le suffixe de date n'est pas ajouté). Les fichiers font également l'objet d'une rotation selon leur taille lorsqu'ils dépassent SAFE_DEP_LOG_MAX_BYTES (10 MiB par défaut ; définissez 0 pour désactiver). Définissez SAFE_DEP_MODEL pour remplacer la valeur du modèle écrite dans source.model pour chaque entrée — utile pour les comparaisons A/B entre versions de modèles.
Les cinq modes écrivent tous leurs entrées dans le même fichier. Chaque entrée porte un bloc source (schéma 2.2) qui identifie le composant qui l'a écrite :
source.component | Écrit par | Déclencheur |
|---|---|---|
shim.posttooluse | shim.sh | Écriture de manifest ou de lockfile (mode Intercept, dispatch Post-Install) |
shim.install_error | shim.sh | Échec de la vérification préalable à l'installation du shim |
bash.pretooluse | pretooluse-bash.sh | Commande d'installation Bash (mode Pre-Install) |
bash.posttooluse | posttooluse-bash.sh | Le hook Bash Post-Install lui-même, lorsqu'il échoue en mode fail-open avant d'atteindre le shim |
agent.pretooluse | pretooluse-agent.sh | Réservé aux événements fail-open Pre-Agent (le hook lui-même est actuellement silencieux en cas de succès) |
agent.posttooluse | posttooluse-agent.sh | Événements fail-open du hook Post-Agent (p. ex. shim manquant, python_missing) |
manual.skill | Claude exécutant le mode Normal | Audit manuel invoqué directement |
source.model enregistre le modèle Claude Code actif dans la session (p. ex. "claude-sonnet-4-6"). Présent dans le schéma 2.1+ ; les entrées écrites par des installations plus anciennes omettent ce champ. La commande stats se replie proprement sur "unknown" lorsqu'il est absent.
Filtrez par source.component avec jq :```bash
jq -r '.source.component' audit.log | sort | uniq -c | sort -rn
jq -c 'select(.source.component == "bash.pretooluse")' audit.log
Surface every silent fail-open across all hooks:
jq -c 'select(.source.mode == "fail_open") | {component: .source.component, reason: .fail_open.reason, ts}' audit.log
Pour une analyse plus facile, demandez à Claude des statistiques d'utilisation au lieu d'analyser les journaux manuellement :```
"Show safer-dependencies stats for the last month"
Ceci fournit des résumés lisibles par un humain de l'activité, de l'impact sur la sécurité et des métriques de performance extraits de ces journaux d'audit.
Formes d’entrée (schéma 2.2). Trois formes distinctes partagent le même en-tête ts / schema / source :
| Forme | Quand elle est écrite | Champs distinctifs |
|---|---|---|
| Entrée d’audit | Audit manifest / lockfile / bash-install | file, ecosystem, checked, findings, abandoned, stale, typosquat, unknown, signatures, notes, clean |
| Entrée d’erreur d’installation | Erreur d’installation preflight du shim (composant shim.install_error) | install_error, shim_dir, scripts_dir |
| Entrée fail-open | Tout point d’entrée de hook se termine prématurément en raison de helper_missing / shim_missing / python_missing. source.mode est "fail_open" | fail_open: { reason, detail? } |
Entrées d’audit : le mode Intercept exécute le pipeline complet (provenance, âge de la version, OSV, abandoned/stale, typosquat, signatures), donc tous les tableaux peuvent être remplis. Le mode Pre-Install n’exécute actuellement qu’OSV, donc abandoned / stale / typosquat / signatures sont toujours vides. Le dispatch Post-Install (audit de lockfile) écrit sous shim.posttooluse avec findings rempli par les chaînes WARNING: des auditeurs de lockfile. Le tableau notes contient des signaux informatifs NOTE: (par ex. manifest-skipped-because-unpinned).
Le schéma 2.2 a ajouté — de manière additive — quatre champs aux entrées d’audit lockfile : lockfile, manifest_ref, relation_summary (une classification directe/transitive/inconnue de chaque paquet signalé par rapport au manifest frère), et un bloc policy enregistrant le niveau transitive en vigueur. Cette évolution est rétrocompatible : les lecteurs des entrées 2.1 tolèrent les nouveaux champs, et le champ source.model reste présent à partir de 2.1.```json
{
"ts": "2026-04-19T12:34:56Z",
"schema": "2.2",
"source": {
"component": "shim.posttooluse",
"script": "shim.sh",
"hook": "PostToolUse:Write",
"tool": "Write",
"mode": "intercept",
"model": "claude-sonnet-4-6"
},
"file": "/path/to/project/package.json",
"ecosystem": "npm",
"checked": ["[email protected]", "[email protected]"],
"findings": ["UPDATED: express 4.18.2 → 4.22.1 (HIGH: 1 CVE fixed)"],
"abandoned": [],
"stale": [],
"typosquat": [],
"unknown": [],
"signatures": [],
"notes": [],
"clean": ["[email protected]"]
}
Exemple du mode pré-installation (hook Bash, PIN vulnérable refusé) :```json
{
"ts": "2026-04-23T06:56:21Z",
"schema": "2.2",
"source": {
"component": "bash.pretooluse",
"script": "pretooluse-bash.sh",
"hook": "PreToolUse:Bash",
"tool": "Bash",
"mode": "intercept",
"model": "claude-sonnet-4-6"
},
"file": "bash:npm install [email protected] [email protected]",
"ecosystem": "npm",
"checked": ["[email protected]", "[email protected]"],
"findings": [
"BLOCKED: [email protected] GHSA-35jh-r3h4-6jhm (CVSS:3.1/...): Command Injection in lodash"
],
"abandoned": [],
"stale": [],
"typosquat": [],
"unknown": [],
"signatures": [],
"notes": [],
"clean": ["[email protected]"]
}
Exemple du mode fail-open (hook Bash post-installation appelé sans shim adjacent — installation cassée) :```json { "ts": "2026-05-03T07:14:11Z", "schema": "2.2", "source": { "component": "bash.posttooluse", "script": "safer-dependencies-posttooluse-bash.sh", "hook": "PostToolUse", "tool": "Bash", "mode": "fail_open", "model": "claude-sonnet-4-6" }, "fail_open": { "reason": "shim_missing", "detail": "/home/alice/.claude/skills/safer-dependencies" } }
Une entrée fail-open indique : « ce hook s'est déclenché mais s'est terminé prématurément sans audit, car un prérequis manquait. » Utilisez le filtre jq ci-dessus (`select(.source.mode == "fail_open")`) pour faire remonter chaque perte silencieuse de protection dans votre journal.
Lorsque le shim s'exécute en mode dry-run (`SAFE_DEP_DRY_RUN=1`), les entrées incluent également `"mode": "dry_run"` afin que l'analyse a posteriori puisse filtrer les invocations d'audit uniquement.
## Prérequis
- Python 3.9+ (les hooks vérifient cela et échouent en fail-open sur les interpréteurs plus anciens)
- `curl` (pour les appels à l'API du registre et les vérifications de vulnérabilités OSV)
- Outils d'écosystème (facultatifs, la compétence se replie sur l'API OSV s'ils sont absents) :
- `npm` pour les paquets npm
- `pip-audit` pour les paquets Python
- `bundle` pour les paquets Ruby
- `dependency-check` pour les paquets Java
## FAQ
La justification des choix de conception (pourquoi `PostToolUse` plutôt que `PreToolUse`, pourquoi les signatures ne sont pas vérifiées, pourquoi les scripts et le shim sont dupliqués, les pièges de chargement de compétence, etc.) est documentée dans [`FAQ.md`](https://github.com/robert-auger/safer-dependencies/blob/HEAD/FAQ.md).