
CLI Python qui crée des dépôts GitHub avec des paramètres par défaut sécurisés — protection des branches, Dependabot, scanning des secrets et analyse de sécurité préalable — appliqués automatiquement.
Créez des dépôts GitHub avec des paramètres par défaut sécurisés appliqués automatiquement. Remplace la liste de vérification des paramètres post-création de cinq minutes par une seule commande.``` gh-safe-repo create <owner/repo>
Protection de branche, tags immuables, Dependabot, permissions Actions restreintes, analyse des secrets avec protection push, ainsi que wiki et projets désactivés — le tout configuré avant même d'écrire votre première ligne de code.
gh-safe-repo est en cours de développement intensif. Il fonctionne bien pour le cas d'usage de création d'un nouveau dépôt avec des paramètres sécurisés par défaut. Je travaille à peaufiner les options CLI pour qu'elles correspondent au mieux aux attentes des utilisateurs. Attendez-vous à des changements potentiellement cassants jusqu'à ce que j'atteigne un stade où je publie des versions et que l'intégration continue / déploiement continu soit bien rodée. ✌️
---
## Table des matières
- [Pourquoi](#why)
- [Ce qu'il modifie](#what-it-changes)
- [Prérequis](#requirements)
- [Installation](#installation)
- [Démarrage rapide](#quick-start)
- [Référence CLI](#cli-reference)
- [Sortie du mode planification / Dry Run](#dry-run--plan-output)
- [Mode Correction (Auditer les dépôts existants)](#fix-mode-audit-existing-repos)
- [Miroir de dépôts (`--from`)](#mirroring-repos---from)
- [Créer un dépôt à partir d'un répertoire local (`--local`)](#creating-a-repo-from-a-local-directory---local)
- [Analyseur de sécurité préalable](#pre-flight-security-scanner)
- [Analyse autonome](#standalone-scan)
- [Suppression des faux positifs](#suppressing-false-positives)
- [Configuration](#configuration)
- [Limitations des plans GitHub](#github-plan-limitations)
- [Comment ça fonctionne](#how-it-works)
- [Développement](#development)
---
## Pourquoi
Les paramètres par défaut des dépôts GitHub sont optimisés pour la découvrabilité et la flexibilité, pas pour la sécurité. Chaque nouveau dépôt est livré avec :
- Wiki et Projets activés (surface d'attaque, même inutilisés)
- Fusion par commit autorisée (historique désordonné, mais ce n'est pas le principal problème)
- Aucune protection de branche (toute personne ayant un accès en écriture peut pousser directement sur `main`)
- Aucune alerte Dependabot
- GitHub Actions avec des permissions d'écriture sur le dépôt
- Actions autorisées à approuver les pull requests
Corriger tout cela manuellement prend plusieurs minutes par dépôt et est facile à oublier. `gh-safe-repo` applique un ensemble de paramètres par défaut pragmatiques mais sécurisés en une seule fois, avec un aperçu du plan afin que vous sachiez exactement ce qui va changer avant que quoi que ce soit ne se produise.
---
## Ce qu'il modifie
### Paramètres du dépôt
| Paramètre | Par défaut GitHub | Par défaut sécurisé | Remarques |
|---|---|---|---|
| Visibilité | Public | **Privé** | Passez `--public` pour modifier |
| Wiki | Activé | **Désactivé** | |
| Projets | Activé | **Désactivé** | |
| Issues | Activé | Activé | |
| Supprimer la branche lors de la fusion | Désactivé | Désactivé | Mettez à `true` dans la configuration pour le nettoyage automatique |
| Autoriser les fusions par commit | Activé | Activé | Mettez à `false` dans la configuration pour les fusions par squash uniquement |
| Autoriser la fusion par squash | Activé | Activé | |
| Autoriser la fusion par rebase | Activé | Activé | |
### GitHub Actions
| Paramètre | Par défaut GitHub | Par défaut sécurisé |
|---|---|---|
| Actions autorisées | Toutes | **Sélectionnées** (appartenant à GitHub + créateurs vérifiés ; personnalisable) |
| Permissions de workflow par défaut | Lecture/écriture | **Lecture seule** |
| Les Actions peuvent approuver les PR | Oui | **Non** |
| Exiger l'épinglage SHA | Non | **Oui** (les workflows doivent épingler les actions à un SHA de commit, pas à un tag mutable) |
| Politique d'approbation des PR de fork | Contributeurs novices nouveaux sur GitHub | **Tous les contributeurs externes** — exiger une approbation avant que les workflows PR de fork n'exécutent le CI. Options : uniquement les nouveaux comptes GitHub (par défaut GitHub), les contributeurs novices du dépôt, ou toutes les PR de fork (le plus sûr) |
### Protection de branche (dépôts publics, ou tout dépôt sur un plan payant)
| Règle | Valeur |
|---|---|
| Exiger une pull request avant fusion | Oui |
| Nombre de critiques approuvées requis | 1 |
| Ignorer les critiques obsolètes lors du push | Oui |
| Exiger la résolution des conversations | Oui |
| Autoriser les pushes forcés | Non |
| Autoriser la suppression de branche | Non |
| Appliquer aux administrateurs | Non (permet aux outils du propriétaire de pousser) |
La protection de branche est appliquée via **l'API Rulesets** par défaut (`use_rulesets = true`) : un seul ruleset `gh-safe-repo defaults` couvre chaque branche configurée et exprime « les administrateurs peuvent contourner » via un acteur de contournement plutôt que par le drapeau classique `enforce_admins`. Définissez `use_rulesets = false` pour le chemin classique par branche hérité (conservé pour un cycle de publication).
**Migration d'un dépôt existant depuis la protection classique :** si `fix` trouve une protection de branche classique sur un dépôt, il refuse de la convertir en ruleset sauf si vous passez `--migrate-branch-protection`. Les règles exclusives classiques n'ont pas d'équivalent dans le ruleset que cet outil construit et seraient abandonnées silencieusement autrement — lacunes connues :
- `required_status_checks` — les vérifications CI requises ne sont pas modélisées dans le corps du ruleset.
- `restrictions` (restrictions de push par utilisateur/équipe) — Rulesets modélise cela différemment via des acteurs de contournement ; ce n'est pas une correspondance 1:1.
- Divergence par branche — un ruleset à condition unique partagée ne peut pas exprimer des règles différentes pour `master` vs `main`.
Avec le drapeau, `fix` crée/met à jour le ruleset puis supprime la protection classique sur chaque branche pour que les deux couches ne s'empilent pas.
### Protection des tags (dépôts publics, ou tout dépôt sur un plan payant)
La protection des tags crée un GitHub Ruleset ciblant tous les tags (`*` par défaut, configurable via `protected_tags`). Les règles suivantes sont appliquées :
| Règle du ruleset | Appliquée ? | Remarques |
|---|---|---|
| Restreindre les créations | Non | |
| **Restreindre les mises à jour** | **Oui** | Empêche la réécriture / le push forcé des tags |
| **Restreindre les suppressions** | **Oui** | Empêche `git push --delete` des tags |
| Exiger un historique linéaire | Non | |
| Exiger le succès des déploiements | Non | |
| Exiger des commits signés | Non | |
| Exiger la réussite des vérifications de statut | Non | |
| Bloquer les pushes forcés | Non | |
Les administrateurs du dépôt sont dans la liste de contournement (conformément au défaut `enforce_admins = false` de la protection de branche). Fonctionne uniquement sur les dépôts publics ou les plans GitHub payants (même restriction que la protection de branche). Les dépôts privés en plan gratuit verront cette étape ignorée dans la sortie du plan.
### Sécurité
| Fonctionnalité | Comportement |
|---|---|
| Alertes Dependabot | Activé (dépôts publics / plans payants) |
| Mises à jour de sécurité Dependabot | Activé (ouvre automatiquement des PR pour les dépendances vulnérables) |
| Analyse des secrets | Automatique sur les dépôts publics ; activé sur les plans privés payants |
| Protection push | Activé (bloque les commits contenant des secrets pris en charge) |
| Signalement privé de vulnérabilités | Activé (permet aux chercheurs de sécurité de signaler en privé) |
| Graphique des dépendances | Automatique sur les dépôts publics ; pas d'API REST pour les dépôts privés (interface uniquement) |
---
## Prérequis
- Python 3.8+
- [`gh` CLI](https://cli.github.com/) installé et authentifié (`gh auth login`), **ou** `GITHUB_TOKEN` défini dans votre environnement
- Pour `--local` / `--from` (qui poussent ou clonent du code) : vos identifiants git habituels doivent être configurés — soit une clé SSH chargée dans `ssh-agent` (lorsque `gh config get git_protocol` est `ssh`) soit un helper d'identification HTTPS (`gh auth setup-git` en configure un automatiquement). Le jeton OAuth **n'est pas** utilisé pour git push, donc les fichiers de workflow (`.github/workflows/*`) se poussent sans nécessiter la portée OAuth `workflow`.
- [`uv`](https://docs.astral.sh/uv/) pour l'installation à partir des sources (recommandé)
- `truffleHog` v3 (optionnel — utilisé par l'analyseur préalable ; détecté automatiquement dans le PATH, ou exécuté via podman/docker ; se rabat sur les expressions régulières si aucun n'est disponible)
---
## Installation
### À partir des sources avec uv (recommandé)```bash
git clone https://github.com/your-username/gh-safe-repo
cd gh-safe-repo
uv tool install .
Cela installe gh-safe-repo dans l'environnement d'outils d'uv et l'ajoute à votre PATH.
git clone https://github.com/your-username/gh-safe-repo cd gh-safe-repo uv sync # creates .venv ./gh-safe-repo create <owner/repo>
### Vérification```bash
gh-safe-repo --help
gh-safe-repo create <owner/repo>
gh-safe-repo create <owner/repo> --dry-run
gh-safe-repo create <owner/repo> --public
gh-safe-repo create <owner/repo> --from <owner/source>
gh-safe-repo create <owner/pub> --from <owner/priv> --public
gh-safe-repo create <owner/repo> --local ~/projects/myapp
gh-safe-repo create <owner/repo> --local ~/projects/myapp --public
gh-safe-repo fix <owner/repo>
gh-safe-repo fix <owner/repo> --dry-run
gh-safe-repo fix <owner/repo> --yes
gh-safe-repo scan . gh-safe-repo scan ~/projects/myapp
## Référence CLI```
gh-safe-repo create <owner/repo> [OPTIONS]
gh-safe-repo fix <owner/repo> [OPTIONS]
gh-safe-repo scan <path> [OPTIONS]
Toutes les commandes qui interagissent avec GitHub nécessitent le format owner/repo (par exemple myuser/my-repo). Pour create, le propriétaire est validé par rapport à votre compte GitHub authentifié pour éviter les erreurs sur les systèmes multi-comptes. Pour fix, des permissions d'administration sur le dépôt cible sont requises à la place, ce qui vous permet de corriger les dépôts appartenant à des organisations ou à d'autres comptes où vous avez un accès administrateur.
create — Créer un nouveau dépôtUn create simple (sans --local/--from) initialise le dépôt pour qu'une branche par défaut existe pour la protection de branche, puis supprime le README.md généré automatiquement afin que le nouveau dépôt démarre proprement. Définissez auto_init = true dans la configuration pour conserver le README à la place. --local/--from poussent votre propre historique et ne créent jamais de README.
fix — Auditer et corriger un dépôt existantscan — Analyse locale des secrets| Option | Description |
|---|---|
--config [PATH] | Chemin vers le fichier de configuration ; --config seul utilise uniquement les valeurs par défaut intégrées |
--debug | Afficher les détails du scanner |
Le code de sortie est 0 si aucun résultat critique, 1 si des résultats critiques sont trouvés.
--dry-run montre exactement ce que ferait gh-safe-repo, sans apporter de modifications ni faire d'appels API. Utilisez-le avant de lancer pour de vrai. Combinez avec --json pour une sortie de plan lisible par machine :```bash
gh-safe-repo create <owner/repo> --dry-run --json
gh-safe-repo fix <owner/repo> --dry-run --json
Lorsque `--json` est actif, le plan est écrit sur stdout sous forme d'objet JSON et tous les autres messages (progression, avertissements, le pied de page "Dry run") vont sur stderr, de sorte que la sortie soit propre pour le piping ou le scripting.```
$ gh-safe-repo create <owner/repo> --dry-run
Plan for my-project (private)
Category Action Setting Value
──────────────────────────────────────────────────────────────────
Repository ADD repository my-project (private)
Repository ADD has_wiki false
Repository ADD has_projects false
Actions ADD default_workflow_permissions read
Actions ADD can_approve_pull_request_reviews false
Branch Protection SKIP branch_protection Not available for private repos on free plan
Security SKIP dependabot_alerts Not available for private repos on free plan
1 setting skipped (GitHub plan limitation).
Dry run — no changes made.
Couleurs des actions :
Sortie JSON (--json):```json
{
"changes": [
{ "type": "add", "category": "repository", "key": "has_wiki", "old": null, "new": false, "reason": null },
{ "type": "skip", "category": "branch_protection", "key": "branch_protection", "old": null, "new": null, "reason": "Not available for private repos on free plan" }
],
"summary": { "add": 5, "skip": 2 }
}
`summary` n'inclut que les types présents dans le plan. Les consommateurs devraient utiliser `.get("delete", 0)` etc. plutôt que de supposer que les quatre clés sont présentes.
---
## Mode Correctif (Audit des Dépôts Existants)
`fix` compare les paramètres actuels d'un dépôt existant avec les valeurs par défaut sûres et applique les corrections nécessaires. Aucun scan de secrets — `fix` concerne uniquement les paramètres du dépôt.```bash
# See what's out of compliance
gh-safe-repo fix <owner/repo> --dry-run
# Apply missing safe defaults
gh-safe-repo fix <owner/repo>
# Apply without confirmation prompt (scripting/batch use)
gh-safe-repo fix <owner/repo> --yes
Mode de correction :
UPDATE pour les réglages modifiés et SKIP pour les réglages déjà à la valeur souhaitée (détection d’opération nulle — il ne fait jamais d’appels API qui ne changeraient rien)--yes)Seuls les changements réels sont appliqués — les réglages déjà à la valeur souhaitée sont affichés comme SKIP et ne génèrent aucun appel API.
--from)--from crée un miroir d’un dépôt existant dans un nouveau dépôt avec des paramètres par défaut sécurisés. Cela fonctionne aussi bien pour les destinations privées que publiques :```bash
gh-safe-repo create <owner/repo> --from <owner/source>
gh-safe-repo create <owner/pub> --from <owner/priv> --public
**Ce qui se passe, dans l'ordre :**
1. Vos identifiants git pour `github.com` sont vérifiés en amont (sonde SSH lorsque `gh config get git_protocol` est `ssh` ; HTTPS est considéré comme sûr), donc une clé manquante échoue rapidement avant la création de tout dépôt
2. Le dépôt source est cloné localement (clone complet, sans `--depth`, afin que truffleHog puisse parcourir l'historique complet des commits)
3. Le [scanner de sécurité pré-vol](#pre-flight-security-scanner) s'exécute sur le clone local
4. Vous examinez les résultats et confirmez (ou annulez)
5. Un nouveau dépôt est créé (privé par défaut, ou public avec `--public`)
6. Les permissions Actions et les paramètres de sécurité sont appliqués (Dependabot, analyse des secrets, protection de push)
7. L'historique complet est reflété : `git clone --mirror` + `git push --mirror`
8. La protection des branches et des tags est appliquée (après le push du code, afin que la branche cible existe)
Si l'analyse révèle un problème et que vous annulez, aucun code n'est jamais copié sur GitHub.
> **Note :** `--from` utilise le format `owner/repo` pour la source et la destination.
---
## Créer un dépôt à partir d'un répertoire local (`--local`)
`--local PATH` est l'équivalent local-à-GitHub de `--from`. Il crée un nouveau dépôt GitHub et envoie le code depuis un dépôt git local. `PATH` doit être un dépôt git initialisé (`git init` ou un clone).```bash
gh-safe-repo create <owner/repo> --local ~/projects/myapp
gh-safe-repo create <owner/repo> --local ~/projects/myapp --public
Ce qui se passe, dans l'ordre :
github.com sont vérifiés en amont (sonde SSH lorsque gh config get git_protocol est ssh ; HTTPS est fiable), donc une clé manquante échoue rapidement avant que tout dépôt ne soit créépush --all --tags (toutes les branches et tous les tags)origin est ajouté au dépôt local original pointant vers la nouvelle URL GitHub, et le suivi amont de la branche courante est configuré — donc git push et git pull fonctionnent immédiatement sans configuration supplémentaire.Les deux --local et --from fonctionnent pour les dépôts privés et publics. Ils sont mutuellement exclusifs.
La branche par défaut locale (via git -C PATH symbolic-ref HEAD) est utilisée pour cibler les règles de protection de branche, donc la protection atterrit sur la bonne branche même si ce n'est pas main.
Astuce : Exécutez
gh-safe-repo scan PATHd'abord si vous voulez inspecter les résultats sans rien créer.
Le scanner s'exécute localement et n'envoie jamais de code à GitHub. Utilisez-le de manière autonome avant tout push, ou il s'exécute automatiquement dans le cadre des workflows --from et --local.
gh-safe-repo scan .
gh-safe-repo scan ~/projects/myapp
Le code de sortie est `0` si aucun résultat critique n'est trouvé, `1` si des résultats critiques sont trouvés — ce qui permet de l'utiliser proprement avec d'autres commandes :```bash
gh-safe-repo scan . && git push
La configuration complète [pre_flight_scan] s'applique : banned_strings, max_file_size_mb, trufflehog_mode, etc.
gh-safe-repo choisit automatiquement le meilleur scanner disponible en utilisant une chaîne de découverte en trois étapes :
trufflehog --version, vérifie qu'il s'agit de la v3, et l'utilise. Une installation v2 ou une version non reconnue affiche un avertissement et passe à l'étape 2.ghcr.io/trufflesecurity/trufflehog:latest) en utilisant podman run ou docker run, en montant le chemin de scan en lecture seule au même chemin absolu afin que les chemins de sortie JSON soient identiques à une exécution native.Le scanner sélectionné est affiché dans l'en-tête "Running pre-flight security scan..." et dans l'entrée SCAN du tableau du plan, par ex. :``` Running pre-flight security scan... (truffleHog v3.93.4) Running pre-flight security scan... (truffleHog via podman) Running pre-flight security scan... (regex only — see warning above)
Variables d'environnement respectées par le chemin du conteneur : `CONTAINER_RUNTIME` pour remplacer la sélection du runtime (par exemple `CONTAINER_RUNTIME=docker`), et `TRUFFLEHOG_IMAGE` pour épingler une étiquette d'image spécifique.
### Exécution de truffleHog via podman ou Docker (sans installation locale)
Aucune configuration manuelle n'est nécessaire. `gh-safe-repo` détecte automatiquement podman ou docker (étape 2 ci-dessus) et exécute truffleHog dans un conteneur avec les bons montages de volume. Les variables d'environnement `CONTAINER_RUNTIME` et `TRUFFLEHOG_IMAGE` sont respectées.
Un wrapper shell (`tools/trufflehog`) et un `Containerfile` pour construire une image locale épinglée sont fournis dans [`tools/`](https://github.com/ariesq/gh-safe-repo/blob/HEAD/tools/README.md) pour les utilisateurs qui souhaitent disposer de truffleHog basé sur un conteneur à l'échelle du système, ou qui ont besoin d'une image isolée (air-gapped).
### Révision interactive```
Pre-flight scan: my-private-project
CRITICAL my_private_project/config.py:12 AWS Access Key ID
[redacted]
WARNING my_private_project/setup.py:3 Email address
author_email="[email protected]"
1 critical finding, 1 warning.
Critical findings detected. Continue anyway? [y/N]:
N). Vous devez taper explicitement y pour continuer.Y). Appuyez sur Entrée pour continuer ou tapez n pour abandonner.Les secrets sont masqués dans la sortie. Les adresses e-mail et les TODOs affichent la ligne correspondante.
Les répertoires d'artefacts de build (node_modules, __pycache__, .venv, venv, dist, build) sont ignorés par défaut pour maintenir la rapidité des analyses. Dans les dépôts git, cette exclusion est conditionnelle : avant de supprimer un répertoire, le scanner exécute git ls-files -- <dir> pour vérifier si des fichiers à l'intérieur sont suivis. Si c'est le cas, le répertoire est analysé normalement.
Cela signifie que les arborescences node_modules ou dist validées — inhabituelles, mais cela arrive — ne sont pas silencieusement ignorées. Les répertoires non validés (le cas normal) continuent d'être ignorés comme avant.
Un avertissement est toujours affiché lorsque des sous-répertoires SKIP_DIRS sont trouvés dans un dépôt source cloné, car leur présence peut indiquer que plus de contenu que prévu est validé.
Deux clés de configuration vous permettent de supprimer les découvertes connues comme sûres sans désactiver des catégories entières de vérification.
scan_exclude_paths — ignorer complètement des fichiers ou répertoires. Les valeurs sont des motifs regex séparés par des sauts de ligne ou des virgules, mis en correspondance avec le chemin relatif du fichier. Un fichier correspondant est exclu de toutes les vérifications : secrets, e-mails, TODOs, gros fichiers et détection des fichiers de contexte IA. Les mêmes motifs sont également transmis à truffleHog via --exclude-paths, afin que la couverture soit cohérente quel que soit le moteur d'analyse actif.```ini
[pre_flight_scan]
scan_exclude_paths = docs/api.github.com.json tests/fixtures/
**`exclude_emails`** — supprimer les résultats d'emails pour des adresses spécifiques ou des domaines entiers. Les valeurs sont séparées par des sauts de ligne ou des virgules, insensibles à la casse. Les entrées commençant par `@` correspondent à tous les emails de ce domaine ; sinon, l'entrée doit correspondre exactement à l'adresse complète. S'applique à la fois aux résultats de l'arbre de travail et de l'historique git.```ini
[pre_flight_scan]
# Suppress bot addresses and placeholder domains
exclude_emails = [email protected], [email protected], @example.com
[pre_flight_scan] scan_for_secrets = true scan_for_emails = true scan_for_todos = true max_file_size_mb = 100
Lorsque des chaînes interdites ou des fichiers de contexte IA sont trouvés, le scanner imprime une commande `git filter-repo` prête à être exécutée pour les supprimer de l'historique du dépôt source avant de le relancer.
---
## Configuration
`gh-safe-repo` recherche la configuration dans cet ordre (la première correspondance l'emporte) :
1. **`--config PATH`** — remplacement explicite
2. **`./gh-safe-repo.ini`** — répertoire de travail actuel
3. **`$XDG_CONFIG_HOME/gh-safe-repo/gh-safe-repo.ini`** — par défaut `~/.config` lorsque `$XDG_CONFIG_HOME` n'est pas défini
`--config` seul (sans chemin) ignore complètement la recherche de fichier et utilise uniquement les valeurs par défaut intégrées.
Toutes les valeurs ont des valeurs par défaut sûres — aucun fichier de configuration n'est requis pour commencer.
Un exemple de configuration entièrement annoté est inclus dans le dépôt sous le nom `gh-safe-repo.ini.example`. Copiez-le pour commencer :```bash
# User-level config (XDG)
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/gh-safe-repo"
cp gh-safe-repo.ini.example "${XDG_CONFIG_HOME:-$HOME/.config}/gh-safe-repo/gh-safe-repo.ini"
# Or project-level config (current directory)
cp gh-safe-repo.ini.example ./gh-safe-repo.ini
[repo]
private = true
has_wiki = false has_projects = false has_issues = true
delete_branch_on_merge = false
allow_squash_merge = true allow_merge_commit = true allow_rebase_merge = true
create leaves an initialized README in the new repo.auto_init = false
[actions]
allowed_actions = selected
github_owned_allowed = true # actions maintained by GitHub (e.g. actions/checkout) verified_allowed = true # actions from Marketplace verified creators
default_workflow_permissions = read
can_approve_pull_request_reviews = false
sha_pinning_required = true
[branch_protection]
protected_branch = main
require_pull_request = true
required_approving_reviews = 1
dismiss_stale_reviews = true
require_conversation_resolution = true
enforce_admins = false
allow_force_pushes = false
allow_deletions = false
use_rulesets = true
[tag_protection]
protected_tags = *
prevent_tag_deletion = true
prevent_tag_update = true
[security]
enable_dependabot_alerts = true
enable_dependabot_security_updates = true
enable_private_vulnerability_reporting = true
enable_secret_scanning_push_protection = true
[pre_flight_scan] scan_for_secrets = true scan_for_emails = true scan_for_todos = true
max_file_size_mb = 100
[git_transport]
workflow token scope to pushworkflow scope intentionally.---
## Limitations du plan GitHub
Certaines fonctionnalités ne sont disponibles qu'en fonction de la visibilité du dépôt et de votre plan GitHub.
| Fonctionnalité | Gratuit + Public | Gratuit + Privé | Pro/Équipe + Privé |
|---|:---:|:---:|:---:|
| Protection de branche / Règles | Oui | Non | Oui |
| Protection des tags (Règles) | Oui | Non | Oui |
| Alertes Dependabot | Oui | Non | Oui |
| Mises à jour de sécurité Dependabot | Oui | Non | Oui |
| Analyse des secrets | Auto | Non | Oui |
| Protection push | Oui | Non | Oui |
| Signalement privé de vulnérabilités | Oui | Oui | Oui |
| Graphe des dépendances | Auto | Non | Oui |
`gh-safe-repo` détecte votre niveau de plan et la visibilité du dépôt au moment de l'exécution. Les fonctionnalités indisponibles apparaissent comme `SKIP` dans la sortie du plan avec une raison claire — l'outil n'échoue jamais silencieusement.
---
## Fonctionnement```
gh-safe-repo create <owner/repo>
│
├─ Parse owner/repo, validate owner matches authenticated user (create only)
├─ Load config (./gh-safe-repo.ini or $XDG_CONFIG_HOME/gh-safe-repo/gh-safe-repo.ini)
├─ Apply CLI flag overrides (--public, etc.)
├─ Authenticate via gh CLI or GITHUB_TOKEN
├─ GET /user → owner login + plan level (single cached call)
│
├─ Build plan (each plugin compares desired vs. current state)
│ ├─ RepositoryPlugin → repo creation + basic settings
│ ├─ ActionsPlugin → allowed actions, workflow permissions, SHA pinning
│ ├─ BranchProtectionPlugin → Rulesets API (default; classic if use_rulesets = false)
│ ├─ SecurityPlugin → Dependabot, secret scanning, push protection, private vuln reporting
│ └─ TagProtectionPlugin → immutable tags via Rulesets API
│
├─ Print plan table
│
└─ Apply (unless --dry-run)
├─ POST /user/repos
├─ PATCH /repos/{owner}/{repo} (settings)
├─ PUT /repos/{owner}/{repo}/actions/permissions/workflow
├─ POST/PATCH /repos/{owner}/{repo}/rulesets (branch protection; default)
│ or PUT /repos/{owner}/{repo}/branches/main/protection (if use_rulesets = false)
├─ PUT /repos/{owner}/{repo}/vulnerability-alerts
├─ PUT /repos/{owner}/{repo}/automated-security-fixes
├─ PUT /repos/{owner}/{repo}/private-vulnerability-reporting
├─ PATCH /repos/{owner}/{repo} (security_and_analysis: push protection)
├─ POST /repos/{owner}/{repo}/rulesets (tag protection ruleset)
├─ git clone --mirror + git push --mirror (if --from)
└─ git clone <local> + git push --all --tags (if --local, git repo)
or git init + add -A + commit + push (if --local, plain dir)
Chaque catégorie de paramètres est une classe de plugin autonome (gh_safe_repo/plugins/). Chaque plugin :
Plan (liste d'objets Change : ADD / UPDATE / DELETE / SKIP)Cela signifie que le mode audit et le mode création utilisent le même chemin de planification/application. La seule différence est que l'état actuel est récupéré depuis un dépôt existant ou supposé être les paramètres par défaut de GitHub.
Les appels API résolvent un jeton dans cet ordre :
GITHUB_TOKEN — permet de cibler un compte spécifique sans changer la session gh active (et c'est la seule information d'identification nécessaire en CI)gh auth token — ce que gh auth login a configuréLes jetons sont passés aux processus enfants gh api en tant que GH_TOKEN dans l'environnement du sous-processus et ne sont jamais consignés.
Les opérations Git (push et clone avec --local / --from) utilisent vos propres informations d'identification git — clé SSH ou assistant d'identification — par défaut, et non le jeton API. Dans les environnements sans aucune de ces options (par exemple, CI avec uniquement GITHUB_TOKEN), l'outil se rabat sur un push via HTTPS avec le jeton dans l'URL ; le paramètre de configuration [git_transport] mode contrôle cela (voir la référence de configuration). Les URL contenant des jetons ne sont jamais écrites dans le .git/config de votre dépôt et sont masquées dans toutes les sorties.
Tous les appels à l'API GitHub passent par gh api via subprocess. Cela maintient l'authentification entièrement dans l'interface en ligne de commande gh — pas de code de gestion de jetons, pas de flux OAuth, pas de verrouillage de version PyGithub. Les corps de requête JSON sont passés via --input - (entrée standard), et non par les flags --field.
git clone https://github.com/your-username/gh-safe-repo cd gh-safe-repo uv sync # creates .venv, installs pytest
uv run pytest tests/ -v
./gh-safe-repo create <owner/repo> --dry-run
uv tool install .
Voir [`tests/README.md`](https://github.com/ariesq/gh-safe-repo/blob/HEAD/tests/README.md) pour les descriptions des fichiers de test, les conventions de simulation, et comment ajouter de nouveaux tests.
### Structure du projet```
gh-safe-repo/
├── gh-safe-repo # Thin launcher (entry point for direct use)
├── gh_safe_repo/ # Package — see gh_safe_repo/README.md for internals
│ ├── cli.py # Subparser dispatch (create, fix, scan)
│ ├── commands/ # Subcommand implementations
│ │ ├── _common.py # Shared helpers, CLIContext, plan formatting
│ │ ├── create.py # create subcommand
│ │ ├── fix.py # fix subcommand
│ │ └── scan.py # scan subcommand
│ └── plugins/ # Settings plugins (one per category)
├── pyproject.toml # Build config, entry points
├── gh-safe-repo.ini.example # Fully annotated example config
└── tests/
Consultez gh_safe_repo/README.md pour la carte des modules, l'architecture des plugins et un guide pour ajouter de nouveaux paramètres.
Il n'y a aucune dépendance d'exécution. Tout utilise la bibliothèque standard Python (argparse, configparser, subprocess, json, re). N'ajoutez pas de paquets tiers sans discussion.
pytest est la seule dépendance de développement, déclarée comme une entrée [dependency-groups] native d'UV dans pyproject.toml.
Ces projets ont été étudiés lors de la conception et ont influencé l'architecture de gh-safe-repo. Ce sont des outils distincts avec des périmètres et des modèles utilisateur différents — consultez docs/LEARNINGS.md pour des notes techniques détaillées sur l'adaptation des motifs.
github/safe-settings — Application GitHub au niveau de l'organisation (Node.js/Probot) qui applique les paramètres de dépôt à partir d'une configuration centrale. Source du motif d'architecture des plugins (une classe par catégorie de paramètre, fetch → diff → apply) et de l'approche de comparaison mergeDeep.
repository-settings/app — Variante plus simple par dépôt de safe-settings, également en Node.js/Probot. A fourni une référence plus propre pour le motif de plugin de base Diffable.
nicholasgasior/gh-repo-settings — Extension CLI écrite en Go avec un workflow plan/apply. Inspiration principale pour le motif d'encapsulation du sous-processus gh api et la conception de la sortie du plan en dry-run.
| Option | Description |
|---|
--public | Créer en tant que dépôt public (par défaut : privé) |
--local PATH | Pousser le code d'un dépôt git local dans le nouveau dépôt. Exécute d'abord une analyse préalable. Mutuellement exclusif avec --from. |
--from OWNER/REPO | Miroir du code d'un dépôt existant dans le nouveau dépôt. Exécute une analyse préalable. Mutuellement exclusif avec --local. |
--yes / -y | Ignorer la demande de confirmation et appliquer immédiatement (pour une utilisation en script/lot) |
--dry-run | Afficher le plan sans apporter de modifications |
--json | Émettre le plan au format JSON vers stdout au lieu du tableau ANSI |
--config [PATH] | Chemin vers le fichier de configuration ; --config seul utilise uniquement les valeurs par défaut intégrées |
--debug | Afficher chaque appel et réponse API |
| Option | Description |
|---|
--yes / -y | Ignorer la demande de confirmation et appliquer immédiatement (pour une utilisation en script/lot) |
--dry-run | Afficher la différence des paramètres sans appliquer les modifications |
--json | Émettre le plan au format JSON vers stdout au lieu du tableau ANSI |
--config [PATH] | Chemin vers le fichier de configuration ; --config seul utilise uniquement les valeurs par défaut intégrées |
--debug | Afficher chaque appel et réponse API, ainsi que l'identité résolue du dépôt (id, nom complet, type de propriétaire) |
| Action |
|---|
| Signification |
|---|
ADD (vert) | Nouveau paramètre appliqué |
UPDATE (jaune) | Paramètre existant modifié (mode audit) |
DELETE (rouge) | Paramètre supprimé |
SKIP (gris) | Aucune action requise — déjà à la valeur souhaitée, ou fonctionnalité indisponible dans votre combinaison plan/visibilité |
| Catégorie | Sévérité | Exemples |
|---|
| Secrets codés en dur | Critique | Clés AWS (AKIA…), jetons GitHub (ghp_…, github_pat_…), clés privées, URL de bases de données |
| Chaînes interdites | Critique | Toute chaîne littérale que vous configurez (noms d'utilisateur, noms d'hôtes internes, noms de code) |
| Fichiers de contexte IA | Critique | CLAUDE.md, AGENTS.md, .cursorrules, copilot-instructions.md, .cursor/ — peuvent contenir des notes de développement internes ; l'historique Git peut être plus sensible que la version actuelle |
| Adresses e-mail | Avertissement | Tout motif [email protected] dans l'arbre de travail et l'historique Git |
| Fichiers volumineux | Avertissement | Fichiers dépassant le seuil de taille configuré (par défaut : 100 Mo) |
| Commentaires TODO/FIXME | Info | # TODO, # FIXME, # HACK, # XXX |