
CLI Python che crea repository GitHub con impostazioni sicure predefinite — protezione dei branch, Dependabot, scansione dei segreti e scansione di sicurezza pre-flight — applicate automaticamente.
Crea repository GitHub con impostazioni predefinite sicure applicate automaticamente. Sostituisce la lista di controllo delle impostazioni post-creazione di cinque minuti con un unico comando.``` gh-safe-repo create <owner/repo>
Protezione dei branch, tag immutabili, Dependabot, autorizzazioni delle Actions limitate, scansione dei segreti con protezione push e wiki e progetti disabilitati — tutto configurato prima di scrivere la prima riga di codice.
gh-safe-repo è in fase di sviluppo intensivo. Funziona bene per il caso d'uso di creare un nuovo repository con impostazioni predefinite sicure. Sto perfezionando le opzioni CLI per allinearle al meglio con le aspettative degli utenti. Ci saranno modifiche sostanziali fino a quando non arriverò a fare release stabili e avrò bloccato il CI/CD. ✌️
---
## Indice
- [Perché](#perché)
- [Cosa modifica](#cosa-modifica)
- [Requisiti](#requisiti)
- [Installazione](#installazione)
- [Avvio rapido](#avvio-rapido)
- [Riferimento CLI](#riferimento-cli)
- [Output di simulazione / piano](#output-di-simulazione--piano)
- [Modalità correzione (controllo repository esistenti)](#modalità-correzione-controllo-repository-esistenti)
- [Duplicazione di repository (`--from`)](#duplicazione-di-repository---from)
- [Creazione di un repository da una directory locale (`--local`)](#creazione-di-un-repository-da-una-directory-locale---local)
- [Scanner di sicurezza pre-volo](#scanner-di-sicurezza-pre-volo)
- [Scansione autonoma](#scansione-autonoma)
- [Soppressione dei falsi positivi](#soppressione-dei-falsi-positivi)
- [Configurazione](#configurazione)
- [Limitazioni dei piani GitHub](#limitazioni-dei-piani-github)
- [Come funziona](#come-funziona)
- [Sviluppo](#sviluppo)
---
## Perché
Le impostazioni predefinite dei repository di GitHub sono ottimizzate per la scopribilità e la flessibilità, non per la sicurezza. Ogni nuovo repository viene fornito con:
- Wiki e Progetti abilitati (superficie d'attacco, anche se non utilizzati)
- Merge commit consentiti (cronologia disordinata, ma non è la preoccupazione principale)
- Nessuna protezione dei branch (chiunque abbia autorizzazioni di scrittura può pushare direttamente su `main`)
- Nessun avviso Dependabot
- GitHub Actions con autorizzazioni di scrittura sul repository
- Actions autorizzate ad approvare pull request
Riparare tutto questo manualmente richiede minuti per repository ed è facile dimenticarlo. `gh-safe-repo` applica un insieme di impostazioni predefinite opinionate ma pratiche in un colpo solo, con un'anteprima del piano in modo da sapere esattamente cosa cambierà prima che accada.
---
## Cosa modifica
### Impostazioni del repository
| Impostazione | Predefinito GitHub | Predefinito sicuro | Note |
|---|---|---|---|
| Visibilità | Pubblico | **Privato** | Passa `--public` per sovrascrivere |
| Wiki | Abilitato | **Disabilitato** | |
| Progetti | Abilitato | **Disabilitato** | |
| Issues | Abilitato | Abilitato | |
| Elimina branch in merge | Off | Off | Imposta su `true` nella configurazione per pulizia automatica |
| Consenti merge commit | On | On | Imposta su `false` nella configurazione per solo squash |
| Consenti squash merge | On | On | |
| Consenti rebase merge | On | On | |
### GitHub Actions
| Impostazione | Predefinito GitHub | Predefinito sicuro |
|---|---|---|
| Actions consentite | Tutte | **Selezionate** (di proprietà GitHub + creatori verificati; personalizzabile) |
| Autorizzazioni predefinite del workflow | Lettura/Scrittura | **Sola lettura** |
| Le Actions possono approvare PR | Sì | **No** |
| Richiedi pinning SHA | No | **Sì** (i workflow devono vincolare le action a uno SHA di commit, non a un tag mutevole) |
| Criterio di approvazione PR da fork | Nuovi contributori su GitHub | **Tutti i contributori esterni** — richiedi approvazione prima che i workflow delle PR da fork eseguano CI. Opzioni: solo account GitHub nuovi (predefinito GitHub), contributori nuovi al repository, o tutte le PR da fork (più sicuro) |
### Protezione dei branch (repository pubblici o qualsiasi repository su piano a pagamento)
| Regola | Valore |
|---|---|
| Richiedi pull request prima del merge | Sì |
| Revisioni approvative richieste | 1 |
| Ignora revisioni obsolete su push | Sì |
| Richiedi risoluzione della conversazione | Sì |
| Consenti force push | No |
| Consenti eliminazione del branch | No |
| Applica agli amministratori | No (consente agli strumenti del proprietario di pushare) |
La protezione dei branch viene applicata tramite l'**API Rulesets** per impostazione predefinita (`use_rulesets = true`): un singolo ruleset `gh-safe-repo defaults` copre ogni branch configurato ed esprime "gli amministratori possono bypassare" tramite un attore di bypass piuttosto che il flag classico `enforce_admins`. Imposta `use_rulesets = false` per il percorso classico legacy per branch (mantenuto per un ciclo di release).
**Migrazione di un repository esistente dalla protezione classica:** se `fix` trova una protezione classica del branch su un repository, rifiuta di convertirla in un ruleset a meno che non si passi `--migrate-branch-protection`. Le regole solo classiche non hanno equivalenti nel ruleset costruito da questo strumento e verrebbero eliminate silenziosamente altrimenti — lacune note:
- `required_status_checks` — i controlli CI richiesti non sono modellati nel corpo del ruleset.
- `restrictions` (restrizioni push per utente/team) — I Rulesets modellano ciò diversamente tramite attori di bypass; non è una mappatura 1:1.
- Divergenza per branch — un ruleset a condizione singola condivisa non può esprimere regole diverse per `master` vs `main`.
Con il flag, `fix` crea/aggiorna il ruleset e poi elimina la protezione classica su ogni branch in modo che i due livelli non si sovrappongano.
### Protezione dei tag (repository pubblici o qualsiasi repository su piano a pagamento)
La protezione dei tag crea un GitHub Ruleset che ha come bersaglio tutti i tag (`*` per impostazione predefinita, configurabile tramite `protected_tags`). Vengono applicate le seguenti regole:
| Regola del ruleset | Applicata? | Note |
|---|---|---|
| Limita creazioni | No | |
| **Limita aggiornamenti** | **Sì** | Impedisce la riscrittura / force-push dei tag |
| **Limita eliminazioni** | **Sì** | Impedisce `git push --delete` dei tag |
| Richiedi cronologia lineare | No | |
| Richiedi che i deployment abbiano successo | No | |
| Richiedi commit firmati | No | |
| Richiedi che i controlli di stato superino | No | |
| Blocca force push | No | |
Gli amministratori del repository sono nella lista di bypass (coerente con l'impostazione predefinita `enforce_admins = false` per la protezione dei branch). Funziona solo su repository pubblici o piani GitHub a pagamento (stessa limitazione della protezione dei branch). I repository privati su piano gratuito vedranno questa voce saltata nell'output del piano.
### Sicurezza
| Funzionalità | Comportamento |
|---|---|
| Avvisi Dependabot | Abilitato (repository pubblici / piani a pagamento) |
| Aggiornamenti di sicurezza Dependabot | Abilitato (apre automaticamente PR per dipendenze vulnerabili) |
| Scansione dei segreti | Automatica sui repository pubblici; abilitata sui piani privati a pagamento |
| Protezione push | Abilitata (blocca i commit che contengono segreti supportati) |
| Segnalazione di vulnerabilità privata | Abilitata (consente ai ricercatori di sicurezza di segnalare in modo privato) |
| Grafico delle dipendenze | Automatico sui repository pubblici; nessuna API REST per i privati (solo UI) |
---
## Requisiti
- Python 3.8+
- CLI [`gh`](https://cli.github.com/) installata e autenticata (`gh auth login`), **oppure** `GITHUB_TOKEN` impostato nell'ambiente
- Per `--local` / `--from` (che inviano o clonano codice): le normali credenziali git devono essere configurate — o una chiave SSH caricata in `ssh-agent` (quando `gh config get git_protocol` è `ssh`) o un helper di credenziali HTTPS (`gh auth setup-git` ne configura uno automaticamente). Il token OAuth **non** viene utilizzato per git push, quindi i file del workflow (`.github/workflows/*`) vengono inviati senza bisogno dell'ambito OAuth `workflow`.
- [`uv`](https://docs.astral.sh/uv/) per l'installazione dal sorgente (consigliato)
- `truffleHog` v3 (opzionale — utilizzato dallo scanner pre-volo; rilevato automaticamente dal PATH, o eseguito tramite podman/docker; se non disponibile, ripiega sulle regex)
---
## Installazione
### Dal sorgente con uv (consigliato)```bash
git clone https://github.com/your-username/gh-safe-repo
cd gh-safe-repo
uv tool install .
Questo installa gh-safe-repo nell'ambiente degli strumenti di uv e lo aggiunge al tuo 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>
### Verifica```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
## Riferimento CLI```
gh-safe-repo create <owner/repo> [OPTIONS]
gh-safe-repo fix <owner/repo> [OPTIONS]
gh-safe-repo scan <path> [OPTIONS]
Tutti i comandi che interagiscono con GitHub richiedono il formato owner/repo (ad es. myuser/my-repo). Per create, il proprietario viene convalidato rispetto al tuo account GitHub autenticato per prevenire errori su sistemi multi-account. Per fix, sono invece richiesti i permessi di amministratore sul repository di destinazione, consentendoti di correggere repository di proprietà di organizzazioni o altri account per cui hai accesso amministrativo.
create — Crea un nuovo repositoryUn semplice create (senza --local/--from) inizializza il repository in modo che esista un ramo predefinito per la protezione del ramo, quindi rimuove il README.md generato automaticamente in modo che il nuovo repository inizi pulito. Imposta auto_init = true nella configurazione per mantenere invece il README. --local/--from inviano la tua cronologia e non creano mai un README.
fix — Analizza e correggi un repository esistentescan — Scansione locale dei segreti| Opzione | Descrizione |
|---|---|
--config [PATH] | Percorso del file di configurazione; --config da solo usa solo le impostazioni predefinite integrate |
--debug | Mostra i dettagli dello scanner |
Il codice di uscita è 0 se non ci sono risultati critici, 1 se vengono trovati critici.
--dry-run mostra esattamente cosa farebbe gh-safe-repo, senza apportare modifiche o chiamate API. Usalo prima di eseguire per davvero. Combinalo con --json per un output del piano leggibile da macchina:```bash
gh-safe-repo create <owner/repo> --dry-run --json
gh-safe-repo fix <owner/repo> --dry-run --json
Quando `--json` è attivo, il piano viene scritto su stdout come oggetto JSON e tutti gli altri messaggi (avanzamento, avvisi, il piè di pagina "Dry run") vanno su stderr, quindi l'output è pulito per piping o 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.
Colori delle azioni:
Output 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` include solo i tipi presenti nel piano. I consumatori dovrebbero usare `.get("delete", 0)` ecc. piuttosto che assumere che tutte e quattro le chiavi siano presenti.
---
## Modalità Fix (Controlla Repo Esistenti)
`fix` confronta le impostazioni attuali di un repo esistente con le impostazioni predefinite sicure e applica eventuali correzioni. Nessuna scansione dei segreti — `fix` riguarda esclusivamente le impostazioni del repo.```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
Modalità di correzione:
UPDATE per le impostazioni modificate e SKIP per quelle già al valore desiderato (rilevamento no-op — non effettua mai chiamate API che non cambierebbero nulla)--yes)Vengono applicate solo le modifiche effettive — le impostazioni già al valore desiderato sono indicate come SKIP e non generano chiamate API.
--from)--from esegue il mirroring di un repository esistente in uno nuovo con impostazioni sicure predefinite. Funziona sia per destinazioni private che pubbliche:```bash
gh-safe-repo create <owner/repo> --from <owner/source>
gh-safe-repo create <owner/pub> --from <owner/priv> --public
**Cosa succede, in ordine:**
1. Le tue credenziali git per `github.com` vengono verificate in anticipo (sonda SSH quando `gh config get git_protocol` è `ssh`; HTTPS è considerato attendibile), quindi una chiave mancante fallisce rapidamente prima che venga creato qualsiasi repository
2. Il repository sorgente viene clonato localmente (clone completo, nessun `--depth`, in modo che truffleHog possa esaminare l'intera cronologia dei commit)
3. Lo [scanner di sicurezza pre-volo](#scanner-di-sicurezza-pre-volo) viene eseguito sul clone locale
4. Esamini i risultati e confermi (o annulli)
5. Viene creato un nuovo repository (privato per impostazione predefinita, o pubblico con `--public`)
6. Vengono applicate le autorizzazioni di Actions e le impostazioni di sicurezza (Dependabot, scansione dei segreti, protezione push)
7. L'intera cronologia viene replicata: `git clone --mirror` + `git push --mirror`
8. Vengono applicate la protezione dei branch e dei tag (dopo il push del codice, in modo che il branch di destinazione esista)
Se la scansione rivela un problema e annulli, nessun codice viene mai copiato su GitHub.
> **Nota:** `--from` utilizza il formato `owner/repo` sia per la sorgente che per la destinazione.
---
## Creazione di un Repository da una Directory Locale (`--local`)
`--local PATH` è la controparte locale di `--from`. Crea un nuovo repository GitHub e invia il codice da un repository git locale. `PATH` deve essere un repository git inizializzato (`git init` o un clone).```bash
gh-safe-repo create <owner/repo> --local ~/projects/myapp
gh-safe-repo create <owner/repo> --local ~/projects/myapp --public
Cosa accade, in ordine:
github.com vengono verificate in anticipo (sonda SSH quando gh config get git_protocol è ssh; HTTPS è considerato attendibile), quindi una chiave mancante fallisce rapidamente prima che venga creato qualsiasi repositorypush --all --tags (tutti i rami e i tag)origin viene aggiunto al repository locale originale che punta al nuovo URL di GitHub, e viene configurato il tracciamento upstream del ramo corrente — in modo che git push e git pull funzionino immediatamente senza configurazioni aggiuntive.Sia --local che --from funzionano per repository privati e pubblici. Si escludono a vicenda.
Il ramo predefinito locale (tramite git -C PATH symbolic-ref HEAD) viene utilizzato per indirizzare le regole di protezione del ramo, quindi la protezione atterra sul ramo corretto anche se non è main.
Suggerimento: Esegui prima
gh-safe-repo scan PATHse vuoi ispezionare i risultati senza creare nulla.
Lo scanner viene eseguito localmente e non invia mai codice a GitHub. Usalo in modo autonomo prima di qualsiasi push, oppure viene eseguito automaticamente come parte dei flussi di lavoro --from e --local.
gh-safe-repo scan .
gh-safe-repo scan ~/projects/myapp
Exit code is `0` if no critical findings, `1` if criticals are found — so it composes cleanly with other commands:```bash
gh-safe-repo scan . && git push
La configurazione completa di [pre_flight_scan] si applica: banned_strings, max_file_size_mb, trufflehog_mode, ecc.
gh-safe-repo seleziona automaticamente il miglior scanner disponibile utilizzando una catena di rilevamento in tre passaggi:
trufflehog --version, verifica che sia v3 e lo utilizza. Un'installazione v2 o una versione non riconosciuta stampa un avviso e passa al passaggio 2.ghcr.io/trufflesecurity/trufflehog:latest) usando podman run o docker run, montando il percorso di scansione in sola lettura allo stesso percorso assoluto in modo che i percorsi dell'output JSON siano identici a una esecuzione nativa.Lo scanner selezionato viene mostrato nell'intestazione "Running pre-flight security scan..." e nella voce SCAN della tabella del piano, ad es.:``` 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)
Variabili d'ambiente rispettate dal percorso del contenitore: `CONTAINER_RUNTIME` per sovrascrivere la selezione del runtime (ad es. `CONTAINER_RUNTIME=docker`), e `TRUFFLEHOG_IMAGE` per fissare un tag immagine specifico.
### Esecuzione di truffleHog tramite podman o Docker (nessuna installazione locale)
Non è richiesta alcuna configurazione manuale. `gh-safe-repo` rileva automaticamente podman o docker (passaggio 2 sopra) ed esegue truffleHog in un contenitore con i corretti mount di volume. Le variabili d'ambiente `CONTAINER_RUNTIME` e `TRUFFLEHOG_IMAGE` sono rispettate.
Un wrapper shell (`tools/trufflehog`) e un `Containerfile` per costruire un'immagine locale fissata sono forniti in [`tools/`](https://github.com/ariesq/gh-safe-repo/blob/HEAD/tools/README.md) per gli utenti che desiderano truffleHog basato su contenitore disponibile a livello di sistema, o che necessitano di un'immagine isolata (air-gapped).
### Revisione interattiva```
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). Devi digitare esplicitamente y per continuare.Y). Premi Invio per procedere o digita n per interrompere.I segreti sono oscurati nell'output. Gli indirizzi email e i TODO mostrano la riga corrispondente.
Le directory degli artefatti di build (node_modules, __pycache__, .venv, venv, dist, build) vengono saltate per impostazione predefinita per mantenere le scansioni veloci. Nei repository git, questa esclusione è condizionale: prima di eliminare una directory, lo scanner esegue git ls-files -- <dir> per verificare se alcuni file al suo interno sono tracciati. Se lo sono, la directory viene scansionata normalmente.
Ciò significa che gli alberi node_modules o dist committati — insoliti, ma capitano — non vengono persi silenziosamente. Le directory non committate (il caso normale) continuano a essere saltate come prima.
Viene comunque stampato un avviso quando le sottodirectory SKIP_DIRS vengono trovate in un repository sorgente clonato, poiché la loro presenza può indicare che è stato committato più contenuto del previsto.
Due chiavi di configurazione ti permettono di sopprimere risultati noti come sicuri senza disabilitare intere categorie di controllo.
scan_exclude_paths — salta interamente file o directory. I valori sono pattern regex separati da nuova riga/virgola confrontati con il percorso relativo del file. Un file corrispondente viene escluso da ogni controllo: segreti, email, TODO, file di grandi dimensioni e rilevamento di file di contesto AI. Gli stessi pattern vengono anche passati a truffleHog tramite --exclude-paths, quindi la copertura è coerente indipendentemente dal motore di scansione attivo.```ini
[pre_flight_scan]
scan_exclude_paths = docs/api.github.com.json tests/fixtures/
**`exclude_emails`** — sopprime i risultati delle email per indirizzi specifici o domini interi. I valori sono separati da nuova riga/virgola e non fanno distinzione tra maiuscole e minuscole. Le voci che iniziano con `@` corrispondono a tutte le email di quel dominio; altrimenti la voce deve corrispondere esattamente all'indirizzo completo. Si applica sia ai risultati dell'albero di lavoro che alla cronologia 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
Quando vengono trovate stringhe vietate o file di contesto AI, lo scanner stampa un comando `git filter-repo` pronto per l'esecuzione per rimuoverli dalla cronologia del repository sorgente prima di eseguire nuovamente la scansione.
---
## Configurazione
`gh-safe-repo` cerca la configurazione in questo ordine (il primo trovato ha la precedenza):
1. **`--config PATH`** — override esplicito
2. **`./gh-safe-repo.ini`** — directory di lavoro corrente
3. **`$XDG_CONFIG_HOME/gh-safe-repo/gh-safe-repo.ini`** — predefinito su `~/.config` se `$XDG_CONFIG_HOME` non è impostato
Il solo `--config` (senza percorso) salta completamente la ricerca del file e utilizza solo i valori predefiniti interni.
Tutti i valori hanno impostazioni predefinite sicure: non è necessario alcun file di configurazione per iniziare.
Un esempio di configurazione completamente annotato è incluso nel repository come `gh-safe-repo.ini.example`. Copialo per iniziare:```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.---
## Limitazioni del Piano GitHub
Alcune funzionalità sono disponibili solo in base alla visibilità del repository e al tuo piano GitHub.
| Funzionalità | Gratuito + Pubblico | Gratuito + Privato | Pro/Team + Privato |
|---|---|:---:|:---:|:---:|
| Protezione rami / Rulesets | Sì | No | Sì |
| Protezione tag (Rulesets) | Sì | No | Sì |
| Avvisi Dependabot | Sì | No | Sì |
| Aggiornamenti di sicurezza Dependabot | Sì | No | Sì |
| Scansione segreti | Auto | No | Sì |
| Protezione push | Sì | No | Sì |
| Segnalazione privata vulnerabilità | Sì | Sì | Sì |
| Grafico delle dipendenze | Auto | No | Sì |
`gh-safe-repo` rileva il livello del tuo piano e la visibilità del repository in fase di esecuzione. Le funzionalità non disponibili appaiono come `SKIP` nell'output del piano con un motivo chiaro — lo strumento non fallisce mai in silenzio.
---
## Come Funziona```
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)
Ogni categoria di impostazioni è una classe plugin autonoma (gh_safe_repo/plugins/). Ogni plugin:
Plan (elenco di oggetti Change: ADD / UPDATE / DELETE / SKIP)Ciò significa che la modalità di audit e la modalità di creazione utilizzano lo stesso percorso di pianificazione/applicazione. L'unica differenza è se lo stato corrente viene recuperato da un repository esistente o si presume siano i predefiniti di GitHub.
Le chiamate API risolvono un token in questo ordine:
GITHUB_TOKEN — ti consente di indirizzare un account specifico senza cambiare la sessione gh attiva (ed è l'unica credenziale necessaria in CI)gh auth token — qualsiasi cosa configurata con gh auth loginI token vengono passati ai processi figli gh api come GH_TOKEN nell'ambiente del sottoprocesso e non vengono mai registrati.
Le operazioni Git (--local / --from push e clone) utilizzano le tue credenziali git — chiave SSH o helper di credenziali — per impostazione predefinita, non il token API. In ambienti senza nessuna delle due (ad esempio CI con solo GITHUB_TOKEN), lo strumento ripiega sul push tramite HTTPS con il token nell'URL; l'impostazione di configurazione [git_transport] mode lo controlla (vedi il riferimento di configurazione). Gli URL contenenti token non vengono mai scritti nel .git/config del tuo repository e vengono oscurati da tutti gli output.
Tutte le chiamate all'API di GitHub passano attraverso gh api tramite subprocess. Questo mantiene l'autenticazione interamente nella CLI gh — nessun codice di gestione dei token, nessun flusso OAuth, nessun pinning di versione di PyGithub. I corpi delle richieste JSON vengono passati tramite --input - (stdin), non flag --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 .
Vedi [`tests/README.md`](https://github.com/ariesq/gh-safe-repo/blob/HEAD/tests/README.md) per descrizioni dei file di test, convenzioni di mocking e come aggiungere nuovi test.
### Struttura del progetto```
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/
Vedi gh_safe_repo/README.md per la mappa dei moduli, l'architettura dei plugin e una guida per aggiungere nuove impostazioni.
Non ci sono dipendenze runtime. Tutto utilizza la libreria standard di Python (argparse, configparser, subprocess, json, re). Non aggiungere pacchetti di terze parti senza discussione.
pytest è l'unica dipendenza di sviluppo, dichiarata come voce [dependency-groups] nativa di UV in pyproject.toml.
Questi progetti sono stati studiati durante la progettazione e hanno influenzato l'architettura di gh-safe-repo. Sono strumenti distinti con diverso ambito e modelli di utente — vedi docs/LEARNINGS.md per note tecniche dettagliate su come i pattern sono stati adattati.
github/safe-settings — App GitHub a livello di organizzazione (Node.js/Probot) che applica le impostazioni del repository da una configurazione centrale. Fonte del pattern di architettura a plugin (una classe per categoria di impostazioni, fetch → diff → apply) e dell'approccio di confronto mergeDeep.
repository-settings/app — Variante più semplice per repository di safe-settings, anch'essa Node.js/Probot. Ha fornito un riferimento più pulito per il pattern di plugin base Diffable.
nicholasgasior/gh-repo-settings — Estensione CLI scritta in Go con un flusso di lavoro plan/apply. Ispirazione principale per il pattern wrapper di subprocesso gh api e il design dell'output del piano dry-run.
| Opzione | Descrizione |
|---|
--public | Crea come repository pubblico (predefinito: privato) |
--local PATH | Invia codice da un repository git locale nel nuovo repository. Esegue prima una scansione pre-verifica. Si esclude a vicenda con --from. |
--from OWNER/REPO | Mirrora il codice da un repository esistente nel nuovo repository. Esegue una scansione pre-verifica. Si esclude a vicenda con --local. |
--yes / -y | Salta la richiesta di conferma e applica immediatamente (per uso script/batch) |
--dry-run | Mostra il piano senza apportare modifiche |
--json | Emetti il piano come JSON su stdout invece della tabella ANSI |
--config [PATH] | Percorso del file di configurazione; --config da solo usa solo le impostazioni predefinite integrate |
--debug | Stampa ogni chiamata e risposta API |
| Opzione | Descrizione |
|---|
--yes / -y | Salta la richiesta di conferma e applica immediatamente (per uso script/batch) |
--dry-run | Mostra le differenze delle impostazioni senza applicare modifiche |
--json | Emetti il piano come JSON su stdout invece della tabella ANSI |
--config [PATH] | Percorso del file di configurazione; --config da solo usa solo le impostazioni predefinite integrate |
--debug | Stampa ogni chiamata e risposta API, più l'identità risolta del repository (id, nome completo, tipo di proprietario) |
| Azione | Significato |
|---|
ADD (green) | Nuova impostazione in applicazione |
UPDATE (yellow) | Impostazione esistente in modifica (modalità audit) |
DELETE (red) | Impostazione in rimozione |
SKIP (dim) | Nessuna azione necessaria — già al valore desiderato, o funzionalità non disponibile per la combinazione piano/visibilità |
| Categoria | Gravità | Esempi |
|---|
| Segreti hardcoded | Critica | Chiavi AWS (AKIA…), token GitHub (ghp_…, github_pat_…), chiavi private, URL di database |
| Stringhe vietate | Critica | Qualsiasi stringa letterale che configuri (nomi utente, hostname interni, nomi in codice) |
| File di contesto AI | Critica | CLAUDE.md, AGENTS.md, .cursorrules, copilot-instructions.md, .cursor/ — possono contenere note di sviluppo interne; la cronologia git può essere più sensibile della versione corrente |
| Indirizzi email | Avviso | Qualsiasi pattern [email protected] nell'albero di lavoro e nella cronologia git |
| File grandi | Avviso | File oltre la soglia di dimensione configurata (default: 100 MB) |
| Commenti TODO/FIXME | Info | # TODO, # FIXME, # HACK, # XXX |