
Python-CLI, die GitHub-Repos mit sicheren Standardeinstellungen erstellt — Branch Protection, Dependabot, Secret Scanning und Pre-Flight-Sicherheitsscans — automatisch angewendet.
Erstelle GitHub-Repositories mit automatisch angewendeten sicheren Standardeinstellungen. Ersetzt die fünfminütige Checkliste für Einstellungen nach der Erstellung durch einen einzigen Befehl.``` gh-safe-repo create <owner/repo>
Branch protection, immutable tags, Dependabot, restricted Actions permissions, secret scanning with push protection, and disabled wiki and projects — all configured before you write your first line of code.
gh-safe-repo befindet sich in intensiver Entwicklung. Es funktioniert gut für den Anwendungsfall, ein neues Repository mit sicheren Standardeinstellungen zu erstellen. Ich arbeite daran, die CLI-Optionen zu verfeinern, um sie bestmöglich an die Erwartungen der Benutzer anzupassen. Rechnen Sie mit bahnbrechenden Änderungen, bis wir an einen Punkt gelangen, an dem ich Releases durchführe und CI/CD fest etabliert habe. ✌️
---
## Table of Contents
- [Warum](#why)
- [Was geändert wird](#what-it-changes)
- [Anforderungen](#requirements)
- [Installation](#installation)
- [Schnellstart](#quick-start)
- [CLI-Referenz](#cli-reference)
- [Trockentest / Planausgabe](#dry-run--plan-output)
- [Behebungsmodus (Vorhandene Repositories prüfen)](#fix-mode-audit-existing-repos)
- [Spiegelung von Repositories (`--from`)](#mirroring-repos---from)
- [Erstellen eines Repos aus einem lokalen Verzeichnis (`--local`)](#creating-a-repo-from-a-local-directory---local)
- [Sicherheitsscanner vor der Ausführung](#pre-flight-security-scanner)
- [Eigenständiger Scan](#standalone-scan)
- [Unterdrücken von Fehlalarmen](#suppressing-false-positives)
- [Konfiguration](#configuration)
- [Einschränkungen des GitHub-Plans](#github-plan-limitations)
- [Wie es funktioniert](#how-it-works)
- [Entwicklung](#development)
---
## Warum
GitHub's Standard-Repository-Einstellungen sind auf Auffindbarkeit und Flexibilität optimiert, nicht auf Sicherheit. Jedes neue Repository wird mitgeliefert mit:
- Wiki und Projekte aktiviert (Angriffsfläche, auch wenn ungenutzt)
- Merge-Commits erlaubt (unübersichtliche Historie, aber nicht das Hauptproblem)
- Kein Branch-Schutz (jeder mit Schreibzugriff kann direkt auf `main` pushen)
- Keine Dependabot-Benachrichtigungen
- GitHub Actions mit Schreibberechtigungen für das Repository
- Actions dürfen Pull-Requests genehmigen
All dies manuell zu beheben dauert Minuten pro Repository und kann leicht vergessen werden. `gh-safe-repo` wendet eine meinungsstarke, aber praktische Reihe von Standardeinstellungen auf einen Schlag an, mit einer Planvorschau, damit Sie genau wissen, was sich ändern wird, bevor etwas passiert.
---
## Was geändert wird
### Repository-Einstellungen
| Einstellung | GitHub-Standard | Sicherer Standard | Anmerkungen |
|---|---|---|---|
| Sichtbarkeit | Öffentlich | **Privat** | Mit `--public` überschreibbar |
| Wiki | Aktiviert | **Deaktiviert** | |
| Projekte | Aktiviert | **Deaktiviert** | |
| Issues | Aktiviert | Aktiviert | |
| Branch nach Merge löschen | Aus | Aus | In der Konfiguration auf `true` setzen für automatische Bereinigung |
| Merge-Commits erlauben | An | An | In der Konfiguration auf `false` setzen für nur Squash |
| Squash-Merge erlauben | An | An | |
| Rebase-Merge erlauben | An | An | |
### GitHub Actions
| Einstellung | GitHub-Standard | Sicherer Standard |
|---|---|---|
| Zugelassene Aktionen | Alle | **Ausgewählt** (GitHub-eigene + verifizierte Ersteller; anpassbar) |
| Standard-Workflow-Berechtigungen | Lesen/Schreiben | **Nur Lesen** |
| Actions können PRs genehmigen | Ja | **Nein** |
| SHA-Pinning erforderlich | Nein | **Ja** (Workflows müssen Aktionen auf einen Commit-SHA pinnen, nicht auf einen veränderbaren Tag) |
| Fork-PR-Genehmigungsrichtlinie | Erstmalige Mitwirkende, neu bei GitHub | **Alle externen Mitwirkenden** — Genehmigung erforderlich, bevor Fork-PR-Workflows CI ausführen. Optionen: nur brandneue GitHub-Konten (GitHub-Standard), erstmalige Repository-Mitwirkende oder alle Fork-PRs (sicherste) |
### Branch-Schutz (öffentliche Repos oder jedes Repo auf einem kostenpflichtigen Plan)
| Regel | Wert |
|---|---|
| Pull-Request vor Zusammenführen erforderlich | Ja |
| Erforderliche genehmigende Überprüfungen | 1 |
| Veraltete Überprüfungen bei Push verwerfen | Ja |
| Auflösung von Unterhaltungen erforderlich | Ja |
| Force-Pushes zulassen | Nein |
| Branch-Löschung zulassen | Nein |
| Bei Administratoren erzwingen | Nein (ermöglicht Owner-Tooling zu pushen) |
Der Branch-Schutz wird standardmäßig über die **Rulesets-API** angewendet (`use_rulesets =
true`): Ein einzelnes `gh-safe-repo defaults`-Ruleset deckt jeden konfigurierten Branch ab und drückt „Administratoren können umgehen“ über einen Bypass-Actor aus, anstatt des klassischen `enforce_admins`-Flags. Setzen Sie `use_rulesets = false` für den veralteten klassischen Pro-Branch-Pfad (für einen Release-Zyklus beibehalten).
**Migration eines vorhandenen Repos vom klassischen Schutz:** Wenn `fix` klassischen Branch-Schutz in einem Repo findet, weigert es sich, ihn in ein Ruleset umzuwandeln, es sei denn, Sie übergeben `--migrate-branch-protection`. Nur-klassische Regeln haben kein Äquivalent im von diesem Tool erstellten Ruleset und würden ansonsten stillschweigend fallen gelassen — bekannte Lücken:
- `required_status_checks` — erforderliche CI-Prüfungen werden im Ruleset-Body nicht modelliert.
- `restrictions` (Push-Einschränkungen nach Benutzer/Team) — Rulesets modellieren dies anders über Bypass-Actors; keine 1:1-Abbildung.
- Pro-Branch-Divergenz — ein einzelnes Ruleset mit gemeinsamer Bedingung kann keine unterschiedlichen Regeln für `master` vs `main` ausdrücken.
Mit dem Flag erstellt/aktualisiert `fix` das Ruleset und löscht dann den klassischen Schutz auf jedem Branch, sodass sich die beiden Ebenen nicht stapeln.
### Tag-Schutz (öffentliche Repos oder jedes Repo auf einem kostenpflichtigen Plan)
Der Tag-Schutz erstellt ein GitHub-Ruleset, das auf alle Tags abzielt (standardmäßig `*`, konfigurierbar über `protected_tags`). Die folgenden Regeln werden durchgesetzt:
| Ruleset-Regel | Durchgesetzt? | Anmerkungen |
|---|---|---|
| Erstellungen einschränken | Nein | |
| **Aktualisierungen einschränken** | **Ja** | Verhindert Umschreiben / Force-Pushen von Tags |
| **Löschungen einschränken** | **Ja** | Verhindert `git push --delete` von Tags |
| Lineare Historie erforderlich | Nein | |
| Erfolgreiche Bereitstellungen erforderlich | Nein | |
| Signierte Commits erforderlich | Nein | |
| Statusprüfungen müssen bestehen | Nein | |
| Force-Pushes blockieren | Nein | |
Repository-Administratoren stehen auf der Bypass-Liste (konsistent mit dem Branch-Schutz-Standard `enforce_admins = false`). Funktioniert nur bei öffentlichen Repos oder kostenpflichtigen GitHub-Plänen (gleiche Einschränkung wie Branch-Schutz). Private Repos im kostenlosen Plan sehen dies in der Planausgabe übersprungen.
### Sicherheit
| Funktion | Verhalten |
|---|---|
| Dependabot-Benachrichtigungen | Aktiviert (öffentliche Repos / kostenpflichtige Pläne) |
| Dependabot-Sicherheitsupdates | Aktiviert (öffnet automatisch PRs für verwundbare Abhängigkeiten) |
| Secret Scanning | Automatisch bei öffentlichen Repos; aktiviert bei privaten kostenpflichtigen Plänen |
| Push-Schutz | Aktiviert (blockiert Commits, die unterstützte Geheimnisse enthalten) |
| Private Meldung von Schwachstellen | Aktiviert (ermöglicht Sicherheitsforschern, privat zu melden) |
| Abhängigkeitsgraph | Automatisch bei öffentlichen Repos; keine REST-API für private (nur UI) |
---
## Anforderungen
- Python 3.8+
- [`gh` CLI](https://cli.github.com/) installiert und authentifiziert (`gh auth login`), **oder** `GITHUB_TOKEN` in Ihrer Umgebung gesetzt
- Für `--local` / `--from` (die Code pushen oder klonen): Ihre üblichen Git-Anmeldedaten müssen eingerichtet sein – entweder ein SSH-Schlüssel, der in `ssh-agent` geladen ist (wenn `gh config get git_protocol` `ssh` ist) oder ein HTTPS-Anmeldehilfsprogramm (`gh auth setup-git` konfiguriert eines automatisch). Das OAuth-Token wird **nicht** für git push verwendet, daher können Workflow-Dateien (`.github/workflows/*`) ohne die OAuth `workflow`-Bereich pushed werden.
- [`uv`](https://docs.astral.sh/uv/) für die Installation aus dem Quellcode (empfohlen)
- `truffleHog` v3 (optional – vom Pre-Flight-Scanner verwendet; wird automatisch aus dem PATH erkannt oder über podman/docker ausgeführt; fällt auf Regex zurück, wenn keines verfügbar ist)
---
## Installation
### Aus dem Quellcode mit uv (empfohlen)```bash
git clone https://github.com/your-username/gh-safe-repo
cd gh-safe-repo
uv tool install .
Dies installiert gh-safe-repo in die Tool-Umgebung von uv und fügt es zu Ihrem PATH hinzu.
git clone https://github.com/your-username/gh-safe-repo cd gh-safe-repo uv sync # creates .venv ./gh-safe-repo create <owner/repo>
### Verifizieren```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
---
## CLI-Referenz```
gh-safe-repo create <owner/repo> [OPTIONS]
gh-safe-repo fix <owner/repo> [OPTIONS]
gh-safe-repo scan <path> [OPTIONS]
All commands that interact with GitHub require the owner/repo format (e.g. myuser/my-repo). For create, the owner is validated against your authenticated GitHub account to prevent mistakes on multi-account systems. For fix, admin permissions on the target repo are required instead, allowing you to fix repos owned by organizations or other accounts where you have admin access.
create — Neues Repository erstellenEin einfaches create (ohne --local/--from) initialisiert das Repository, sodass ein Standardbranch für den Branchschutz existiert, und entfernt dann die automatisch generierte README.md, damit das neue Repository sauber startet. Setze auto_init = true in der Konfiguration, um die README stattdessen zu behalten. --local/--from pushen Ihre eigene Historie und erstellen niemals eine README.
fix — Vorhandenes Repository prüfen und reparierenscan — Lokales Secret-Scanning| Option | Beschreibung |
|---|---|
--config [PATH] | Pfad zur Konfigurationsdatei; reines --config verwendet nur die integrierten Standardeinstellungen |
--debug | Scanner-Details anzeigen |
Der Exit-Code ist 0, wenn keine kritischen Funde vorliegen, 1, wenn kritische Funde vorhanden sind.
--dry-run zeigt genau, was gh-safe-repo tun würde, ohne Änderungen vorzunehmen oder API-Aufrufe durchzuführen. Verwenden Sie es vor der tatsächlichen Ausführung. Kombinieren Sie es mit --json für maschinenlesbare Planausgabe:```bash
gh-safe-repo create <owner/repo> --dry-run --json
gh-safe-repo fix <owner/repo> --dry-run --json
Wenn `--json` aktiv ist, wird der Plan als JSON-Objekt auf stdout geschrieben und alle anderen Nachrichten (Fortschritt, Warnungen, die "Trockenlauf"-Fußzeile) gehen nach stderr, sodass die Ausgabe für Piping oder Scripting sauber bleibt.```
$ 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.
Aktionsfarben:
JSON-Ausgabe (--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` enthält nur Typen, die im Plan vorhanden sind. Verwender sollten `.get("delete", 0)` etc. verwenden, anstatt davon auszugehen, dass alle vier Schlüssel vorhanden sind.
---
## Fix-Modus (Audit bestehender Repos)
`fix` vergleicht die aktuellen Einstellungen eines bestehenden Repos mit den sicheren Standardwerten und wendet ggf. Korrekturen an. Kein Secret-Scanning — `fix` bezieht sich ausschließlich auf Repo-Einstellungen.```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
Fix-Modus:
UPDATE für geänderte Einstellungen und SKIP für Einstellungen, die bereits den gewünschten Wert haben (Null-Operation-Erkennung — es werden niemals API-Aufrufe getätigt, die nichts ändern würden)--yes)Es werden nur tatsächliche Änderungen angewendet — Einstellungen, die bereits den gewünschten Wert haben, werden als SKIP angezeigt und verursachen keine API-Aufrufe.
--from)--from spiegelt ein vorhandenes Repository in ein neues mit sicheren Standardwerten. Es funktioniert sowohl für private als auch für öffentliche Ziele:```bash
gh-safe-repo create <owner/repo> --from <owner/source>
gh-safe-repo create <owner/pub> --from <owner/priv> --public
**Was passiert in dieser Reihenfolge:**
1. Ihre Git-Anmeldedaten für `github.com` werden vorab überprüft (SSH-Überprüfung, wenn `gh config get git_protocol` auf `ssh` gesetzt ist; HTTPS wird als vertrauenswürdig eingestuft), sodass ein fehlender Schlüssel einen schnellen Fehler verursacht, bevor ein Repository erstellt wird.
2. Das Quell-Repository wird lokal geklont (vollständiger Klon, ohne `--depth`, damit truffleHog den gesamten Commit-Verlauf durchlaufen kann).
3. Der [Sicherheits-Scanner vor dem Start](#pre-flight-security-scanner) wird auf dem lokalen Klon ausgeführt.
4. Sie überprüfen die Ergebnisse und bestätigen (oder brechen ab).
5. Ein neues Repository wird erstellt (standardmäßig privat oder mit `--public` öffentlich).
6. Berechtigungen für Aktionen und Sicherheitseinstellungen werden angewendet (Dependabot, Secret Scanning, Push Protection).
7. Der gesamte Verlauf wird gespiegelt: `git clone --mirror` + `git push --mirror`.
8. Branch- und Tag-Schutz werden angewendet (nach dem Code-Push, sodass der Ziel-Branch existiert).
Wenn der Scan ein Problem aufdeckt und Sie abbrechen, wird kein Code jemals auf GitHub kopiert.
> **Hinweis:** `--from` verwendet das Format `owner/repo` sowohl für die Quelle als auch für das Ziel.
---
## Erstellen eines Repositorys aus einem lokalen Verzeichnis (`--local`)
`--local PFAD` ist das lokale Pendant zu `--from` für das Hochladen nach GitHub. Es erstellt ein neues GitHub-Repository und überträgt Code aus einem lokalen Git-Repository. `PFAD` muss ein initialisiertes Git-Repository sein (`git init` oder ein Klon).```bash
gh-safe-repo create <owner/repo> --local ~/projects/myapp
gh-safe-repo create <owner/repo> --local ~/projects/myapp --public
Was passiert, in der Reihenfolge:
github.com werden vorab überprüft (SSH-Sonde, wenn gh config get git_protocol ssh ist; HTTPS wird vertraut), sodass ein fehlender Schlüssel schnell fehlschlägt, bevor ein Repository erstellt wird.push --all --tags gepusht (alle Branches und Tags).origin wird dem ursprünglichen lokalen Repository hinzugefügt, das auf die neue GitHub-URL zeigt, und das Upstream-Tracking des aktuellen Branches wird konfiguriert – so funktionieren git push und git pull sofort ohne zusätzliche Einrichtung.Sowohl --local als auch --from funktionieren für private und öffentliche Repos. Sie schließen sich gegenseitig aus.
Der lokale Standard-Branch (über git -C PATH symbolic-ref HEAD) wird verwendet, um Branch-Schutzregeln zu zielen, sodass der Schutz auf dem richtigen Branch landet, auch wenn es nicht main ist.
Tipp: Führen Sie zuerst
gh-safe-repo scan PATHaus, wenn Sie Ergebnisse inspizieren möchten, ohne etwas zu erstellen.
Der Scanner läuft lokal und sendet niemals Code an GitHub. Verwenden Sie ihn eigenständig vor einem Push, oder er läuft automatisch als Teil der --from- und --local-Workflows.
gh-safe-repo scan .
gh-safe-repo scan ~/projects/myapp
Exit-Code ist `0`, wenn keine kritischen Ergebnisse vorliegen, `1`, wenn kritische Ergebnisse gefunden werden — so lässt es sich sauber mit anderen Befehlen kombinieren:```bash
gh-safe-repo scan . && git push
Die vollständige [pre_flight_scan]-Konfiguration gilt: banned_strings, max_file_size_mb, trufflehog_mode usw.
gh-safe-repo wählt automatisch den besten verfügbaren Scanner über eine dreistufige Erkennungskette aus:
trufflehog --version aus, überprüft, ob es sich um v3 handelt, und verwendet es. Eine v2-Installation oder eine nicht erkannte Version gibt eine Warnung aus und fällt auf Schritt 2 zurück.ghcr.io/trufflesecurity/trufflehog:latest) mit podman run oder docker run aus, wobei der Scan-Pfad schreibgeschützt unter demselben absoluten Pfad eingebunden wird, sodass die JSON-Ausgabepfade mit einem nativen Durchlauf identisch sind.Der ausgewählte Scanner wird im Header "Running pre-flight security scan..." und im SCAN-Eintrag der Plantabelle angezeigt, z.B.:``` 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)
Umgebungsvariablen, die vom Container-Pfad beachtet werden: `CONTAINER_RUNTIME` zur Überschreibung der Laufzeitauswahl (z.B. `CONTAINER_RUNTIME=docker`) und `TRUFFLEHOG_IMAGE` zum Festlegen eines bestimmten Image-Tags.
### Ausführen von truffleHog über podman oder Docker (keine lokale Installation)
Es ist keine manuelle Einrichtung erforderlich. `gh-safe-repo` erkennt podman oder docker automatisch (Schritt 2 oben) und führt truffleHog in einem Container mit den korrekten Volume-Mounts aus. Die Umgebungsvariablen `CONTAINER_RUNTIME` und `TRUFFLEHOG_IMAGE` werden beachtet.
Ein Shell-Wrapper (`tools/trufflehog`) und eine `Containerfile` zum Erstellen eines festgelegten lokalen Images werden in [`tools/`](https://github.com/ariesq/gh-safe-repo/blob/HEAD/tools/README.md) für Benutzer bereitgestellt, die containerbasiertes truffleHog systemweit verfügbar haben möchten oder ein abgeschirmtes Image benötigen.
### Interaktive Überprüfung```
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). Sie müssen explizit y eingeben, um fortzufahren.Y). Drücken Sie die Eingabetaste, um fortzufahren, oder geben Sie n ein, um abzubrechen.Geheimnisse werden in der Ausgabe geschwärzt. E-Mail-Adressen und TODOs zeigen die zugehörige Zeile an.
Build-Artefakt-Verzeichnisse (node_modules, __pycache__, .venv, venv, dist, build) werden standardmäßig übersprungen, um die Scans schnell zu halten. In Git-Repos ist dieses Überspringen bedingt: Bevor ein Verzeichnis ausgelassen wird, führt der Scanner git ls-files -- <dir> aus, um zu prüfen, ob darin enthaltene Dateien versioniert sind. Ist dies der Fall, wird das Verzeichnis normal gescannt.
Das bedeutet, dass versionierte node_modules- oder dist-Bäume – ungewöhnlich, aber es kommt vor – nicht stillschweigend übersehen werden. Nicht versionierte Verzeichnisse (der Normalfall) werden weiterhin wie zuvor übersprungen.
Eine Warnung wird dennoch ausgegeben, wenn SKIP_DIRS-Unterverzeichnisse in einem geklonten Quell-Repository gefunden werden, da ihr Vorhandensein darauf hindeuten kann, dass mehr Inhalte als erwartet versioniert sind.
Zwei Konfigurationsschlüssel ermöglichen es Ihnen, bekannte sichere Funde zu unterdrücken, ohne ganze Prüfkategorien zu deaktivieren.
scan_exclude_paths — überspringt Dateien oder Verzeichnisse vollständig. Werte sind durch Zeilenumbrüche/Kommata getrennte Regex-Muster, die gegen den relativen Dateipfad geprüft werden. Eine übereinstimmende Datei wird von jeder Prüfung ausgeschlossen: Geheimnisse, E-Mails, TODOs, große Dateien und KI-Kontextdatei-Erkennung. Dieselben Muster werden auch an truffleHog über --exclude-paths übergeben, sodass die Abdeckung unabhängig vom aktiven Scanner-Engine konsistent ist.```ini
[pre_flight_scan]
scan_exclude_paths = docs/api.github.com.json tests/fixtures/
**`exclude_emails`** — unterdrückt E-Mail-Funde für bestimmte Adressen oder ganze Domänen. Werte werden zeilen-/kommasepariert angegeben, Groß-/Kleinschreibung wird ignoriert. Einträge, die mit `@` beginnen, stimmen mit allen E-Mails dieser Domäne überein; andernfalls muss der Eintrag exakt mit der vollständigen Adresse übereinstimmen. Gilt sowohl für Arbeitsverzeichnis- als auch Git-Verlaufs-Funde.```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
Wenn gesperrte Zeichenfolgen oder KI-Kontextdateien gefunden werden, gibt der Scanner einen sofort ausführbaren `git filter-repo`-Befehl aus, um sie aus dem Verlauf des Quell-Repositoriums zu entfernen, bevor es erneut ausgeführt wird.
---
## Konfiguration
`gh-safe-repo` sucht in dieser Reihenfolge nach Konfigurationen (der erste Treffer gewinnt):
1. **`--config PFAD`** — explizite Überschreibung
2. **`./gh-safe-repo.ini`** — aktuelles Arbeitsverzeichnis
3. **`$XDG_CONFIG_HOME/gh-safe-repo/gh-safe-repo.ini`** — standardmäßig auf `~/.config`, wenn `$XDG_CONFIG_HOME` nicht gesetzt ist
Ein nacktes `--config` (ohne Pfad) überspringt die Dateisuche vollständig und verwendet nur die integrierten Standardeinstellungen.
Alle Werte haben sichere Standardeinstellungen — es ist keine Konfigurationsdatei erforderlich, um loszulegen.
Eine vollständig kommentierte Beispielkonfiguration ist im Repository als `gh-safe-repo.ini.example` enthalten. Kopieren Sie sie, um loszulegen:```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.---
## Einschränkungen des GitHub-Plans
Einige Funktionen sind nur abhängig von der Sichtbarkeit des Repos und Ihrem GitHub-Plan verfügbar.
| Funktion | Kostenlos + Öffentlich | Kostenlos + Privat | Pro/Team + Privat |
|---|:---:|:---:|:---:|
| Branch-Schutz / Regelsets | Ja | Nein | Ja |
| Tag-Schutz (Regelsets) | Ja | Nein | Ja |
| Dependabot-Warnungen | Ja | Nein | Ja |
| Dependabot-Sicherheitsupdates | Ja | Nein | Ja |
| Secret-Scanning | Automatisch | Nein | Ja |
| Push-Schutz | Ja | Nein | Ja |
| Private Sicherheitslückenmeldung | Ja | Ja | Ja |
| Abhängigkeitsgraph | Automatisch | Nein | Ja |
`gh-safe-repo` erkennt Ihren Plantarif und die Reposichtbarkeit zur Laufzeit. Nicht verfügbare Funktionen erscheinen als `SKIP` in der Planausgabe mit einer klaren Begründung — das Werkzeug schlägt nie still fehl.
---
## So funktioniert es```
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)
Jede Einstellungskategorie ist eine eigenständige Plugin-Klasse (gh_safe_repo/plugins/). Jedes Plugin:
Plan zurück (Liste von Change-Objekten: ADD / UPDATE / DELETE / SKIP)Das bedeutet, dass der Audit-Modus und der Erstellungsmodus denselben Plan/Apply-Pfad verwenden. Der einzige Unterschied besteht darin, ob der aktuelle Status von einem vorhandenen Repository abgerufen oder als GitHub-Standard angenommen wird.
API-Aufrufe lösen einen Token in dieser Reihenfolge auf:
GITHUB_TOKEN-Umgebungsvariable — ermöglicht es, ein bestimmtes Konto anzusprechen, ohne die aktive gh-Sitzung zu wechseln (und ist die einzige Anmeldeinformation, die in CI benötigt wird)gh auth token — was auch immer gh auth login eingerichtet hatTokens werden an untergeordnete gh api-Prozesse als GH_TOKEN in der Subprozess-Umgebung übergeben und niemals protokolliert.
Git-Operationen (--local / --from push und clone) verwenden standardmäßig Ihre eigenen Git-Anmeldeinformationen — SSH-Schlüssel oder Credential Helper —, nicht den API-Token. In Umgebungen ohne beides (z. B. CI mit nur GITHUB_TOKEN) weicht das Tool auf HTTPS-Push mit dem Token in der URL aus; die Konfigurationseinstellung [git_transport] mode steuert dies (siehe die Konfigurationsreferenz). Token-tragende URLs werden niemals in das .git/config Ihres Repositorys geschrieben und aus allen Ausgaben entfernt.
Alle GitHub-API-Aufrufe erfolgen über gh api mittels subprocess. Dadurch bleibt die Authentifizierung vollständig in der gh-CLI — kein Token-Management-Code, kein OAuth-Flow, kein PyGithub-Versions-Fixing. JSON-Anfragekörper werden über --input - (stdin) übergeben, nicht über --field-Flags.
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 .
Siehe [`tests/README.md`](https://github.com/ariesq/gh-safe-repo/blob/HEAD/tests/README.md) für Testdateibeschreibungen, Mock-Konventionen und Anleitung zum Hinzufügen neuer Tests.
### Projektstruktur```
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/
Siehe gh_safe_repo/README.md für die Modulkarte, Plugin-Architektur und eine Anleitung zum Hinzufügen neuer Einstellungen.
Es gibt keine Laufzeitabhängigkeiten. Alles verwendet die Python-Standardbibliothek (argparse, configparser, subprocess, json, re). Fügen Sie keine Drittanbieter-Pakete ohne Diskussion hinzu.
pytest ist die einzige Entwicklungsabhängigkeit, deklariert als UV-nativer [dependency-groups]-Eintrag in pyproject.toml.
Diese Projekte wurden während des Designs untersucht und haben die Architektur von gh-safe-repo beeinflusst. Sie sind eigenständige Werkzeuge mit unterschiedlichem Umfang und Benutzermodellen — siehe docs/LEARNINGS.md für detaillierte technische Hinweise zur Anpassung von Mustern.
github/safe-settings — GitHub-App auf Organisationsebene (Node.js/Probot), die Repository-Einstellungen aus einer zentralen Konfiguration durchsetzt. Quelle des Plugin-Architekturmusters (eine Klasse pro Einstellungskategorie, fetch → diff → apply) und des mergeDeep-Vergleichsansatzes.
repository-settings/app — Einfachere pro-Repo-Variante von safe-settings, ebenfalls Node.js/Probot. Bietet eine sauberere Referenz für das Diffable-Basis-Plugin-Muster.
nicholasgasior/gh-repo-settings — CLI-Erweiterung in Go mit einem plan/apply-Workflow. Hauptinspiration für das gh api-Subprocess-Wrapper-Muster und das Design der Trockenlauf-Planausgabe.
| Option | Beschreibung |
|---|
--public | Als öffentliches Repository erstellen (Standard: privat) |
--local PATH | Code aus einem lokalen Git-Repository in das neue Repository pushen. Führt zuerst einen Pre-Flight-Scan durch. Schließt sich mit --from gegenseitig aus. |
--from OWNER/REPO | Code aus einem bestehenden Repository in das neue Repository spiegeln. Führt Pre-Flight-Scan durch. Schließt sich mit --local gegenseitig aus. |
--yes / -y | Bestätigungsaufforderung überspringen und sofort anwenden (für Skript-/Batch-Nutzung) |
--dry-run | Plan anzeigen, ohne Änderungen vorzunehmen |
--json | Plan als JSON an stdout ausgeben, anstatt der ANSI-Tabelle |
--config [PATH] | Pfad zur Konfigurationsdatei; reines --config verwendet nur die integrierten Standardeinstellungen |
--debug | Jeden API-Aufruf und jede Antwort ausgeben |
| Option | Beschreibung |
|---|
--yes / -y | Bestätigungsaufforderung überspringen und sofort anwenden (für Skript-/Batch-Nutzung) |
--dry-run | Einstellungsunterschied anzeigen, ohne Änderungen anzuwenden |
--json | Plan als JSON an stdout ausgeben, anstatt der ANSI-Tabelle |
--config [PATH] | Pfad zur Konfigurationsdatei; reines --config verwendet nur die integrierten Standardeinstellungen |
--debug | Jeden API-Aufruf und jede Antwort ausgeben, plus die aufgelöste Repository-Identität (ID, vollständiger Name, Besitzertyp) |
| Aktion | Bedeutung |
|---|
ADD (grün) | Neue Einstellung wird angewendet |
UPDATE (gelb) | Bestehende Einstellung wird geändert (Prüfmodus) |
DELETE (rot) | Einstellung wird entfernt |
SKIP (gedimmt) | Keine Aktion erforderlich — bereits beim gewünschten Wert, oder Funktion für Ihre Kombination aus Plan/Sichtbarkeit nicht verfügbar |
| Kategorie | Schweregrad | Beispiele |
|---|
| Hartcodierte Geheimnisse | Kritisch | AWS-Schlüssel (AKIA…), GitHub-Tokens (ghp_…, github_pat_…), private Schlüssel, Datenbank-URLs |
| Verbotene Zeichenfolgen | Kritisch | Alle von Ihnen konfigurierten literalen Zeichenfolgen (Benutzernamen, interne Hostnamen, Codenamen) |
| KI-Kontextdateien | Kritisch | CLAUDE.md, AGENTS.md, .cursorrules, copilot-instructions.md, .cursor/ — können interne Entwicklernotizen enthalten; der Git-Verlauf kann sensibler sein als die aktuelle Version |
| E-Mail-Adressen | Warnung | Jedes [email protected]-Muster im Arbeitsbaum und im Git-Verlauf |
| Große Dateien | Warnung | Dateien, die die konfigurierte Größenschwelle überschreiten (Standard: 100 MB) |
| TODO/FIXME-Kommentare | Info | # TODO, # FIXME, # HACK, # XXX |