创建自动应用安全默认设置的GitHub仓库。用一个命令取代创建后需要五分钟检查的设置清单。``` gh-safe-repo create <owner/repo>
分支保护、不可变标签、Dependabot、受限的 Actions 权限、带有推送保护的密钥扫描,以及禁用的 Wiki 和 Projects——所有这些在你编写第一行代码之前就已配置完毕。
gh-safe-repo 正处于重度开发阶段。它对于使用安全默认值创建新仓库的场景表现出色。我正在努力完善 CLI 选项,以更好地符合用户预期。在发展到发布版本并稳定 CI/CD 之前,预计会有破坏性变更。✌️
---
## 目录
- [为什么](#为什么)
- [它改变了什么](#它改变了什么)
- [要求](#要求)
- [安装](#安装)
- [快速开始](#快速开始)
- [CLI 参考](#cli-参考)
- [模拟运行/计划输出](#模拟运行计划输出)
- [修复模式(审计现有仓库)](#修复模式审计现有仓库)
- [镜像仓库(`--from`)](#镜像仓库---from)
- [从本地目录创建仓库(`--local`)](#从本地目录创建仓库---local)
- [预检安全扫描器](#预检安全扫描器)
- [独立扫描](#独立扫描)
- [抑制误报](#抑制误报)
- [配置](#配置)
- [GitHub 计划限制](#github-计划限制)
- [工作原理](#工作原理)
- [开发](#开发)
---
## 为什么
GitHub 的默认仓库设置针对可发现性和灵活性进行了优化,而非安全性。每个新仓库都附带:
- Wiki 和 Projects 已启用(攻击面,即使未使用)
- 允许合并提交(历史混乱,但并非主要问题)
- 无分支保护(任何具有写入权限的人都可以直接推送到 `main`)
- 无 Dependabot 警报
- GitHub Actions 具有对仓库的写入权限
- Actions 允许批准 PR
手动修复所有这些设置每个仓库需要几分钟,而且很容易忘记。`gh-safe-repo` 一次性应用一套有主见但实用的默认设置,并提供计划预览,让你在执行任何更改之前确切知道将要更改的内容。
---
## 它改变了什么
### 仓库设置
| 设置 | GitHub 默认值 | 安全默认值 | 备注 |
|---|---|---|---|
| 可见性 | 公开 | **私有** | 传递 `--public` 以覆盖 |
| Wiki | 启用 | **禁用** | |
| Projects | 启用 | **禁用** | |
| Issues | 启用 | 启用 | |
| 合并后删除分支 | 关闭 | 关闭 | 在配置中设置为 `true` 以自动清理 |
| 允许合并提交 | 开启 | 开启 | 在配置中设置为 `false` 以仅允许压缩合并 |
| 允许压缩合并 | 开启 | 开启 | |
| 允许变基合并 | 开启 | 开启 | |
### GitHub Actions
| 设置 | GitHub 默认值 | 安全默认值 |
|---|---|---|
| 允许的操作 | 全部 | **选定**(GitHub 拥有 + 已验证创建者;可自定义) |
| 默认工作流权限 | 读/写 | **只读** |
| Actions 可以批准 PR | 是 | **否** |
| 要求 SHA 固定 | 否 | **是**(工作流必须将操作固定到提交 SHA,而非可变标签) |
| Fork PR 批准策略 | 首次贡献者(新 GitHub 用户) | **所有外部贡献者**——在 fork PR 工作流运行 CI 之前需要批准。选项:仅全新 GitHub 账户(GitHub 默认)、仓库首次贡献者、或所有 fork PR(最安全) |
### 分支保护(公开仓库,或任何付费计划上的仓库)
| 规则 | 值 |
|---|---|
| 合并前要求拉取请求 | 是 |
| 所需批准审查数 | 1 |
| 推送时忽略过期的审查 | 是 |
| 要求解决对话 | 是 |
| 允许强制推送 | 否 |
| 允许删除分支 | 否 |
| 对管理员强制执行 | 否(允许所有者工具进行推送) |
分支保护默认通过 **规则集 API** 应用(`use_rulesets = true`):一个单一的 `gh-safe-repo defaults` 规则集覆盖每个已配置的分支,并通过绕过参与者而非经典的 `enforce_admins` 标志来表示“管理员可以绕过”。设置 `use_rulesets = false` 以使用传统的每个分支经典路径(保留一个发布周期)。
**从经典保护迁移现有仓库:** 如果 `fix` 在仓库上发现经典分支保护,除非传递 `--migrate-branch-protection`,否则拒绝将其转换为规则集。仅限经典的规则在该工具构建的规则集中没有等效项,否则会静默丢弃——已知差距:
- `required_status_checks`——规则集主体中未建模所需的 CI 检查。
- `restrictions`(按用户/团队的推送限制)——规则集通过绕过参与者以不同方式建模,非 1:1 映射。
- 每个分支的差异——单个共享条件规则集无法为 `master` 和 `main` 表达不同规则。
使用该标志时,`fix` 创建/更新规则集,然后删除每个分支上的经典保护,以避免两层叠加。
### 标签保护(公开仓库,或任何付费计划上的仓库)
标签保护创建一个 GitHub 规则集,针对所有标签(默认 `*`,可通过 `protected_tags` 配置)。强制实施以下规则:
| 规则集规则 | 强制实施? | 备注 |
|---|---|---|
| 限制创建 | 否 | |
| **限制更新** | **是** | 防止重写/强制推送标签 |
| **限制删除** | **是** | 防止 `git push --delete` 标签 |
| 要求线性历史 | 否 | |
| 要求部署成功 | 否 | |
| 要求签名提交 | 否 | |
| 要求状态检查通过 | 否 | |
| 阻止强制推送 | 否 | |
仓库管理员在绕过列表中(与分支保护 `enforce_admins = false` 默认值一致)。仅适用于公开仓库或付费 GitHub 计划(与分支保护相同限制)。免费计划的私有仓库将在计划输出中看到此步骤被跳过。
### 安全
| 功能 | 行为 |
|---|---|
| Dependabot 警报 | 启用(公开仓库/付费计划) |
| Dependabot 安全更新 | 启用(自动打开易受攻击依赖项的 PR) |
| 密钥扫描 | 公开仓库自动;私有付费计划启用 |
| 推送保护 | 启用(阻止包含支持密钥的提交) |
| 私有漏洞报告 | 启用(允许安全研究人员私下报告) |
| 依赖关系图 | 公开仓库自动;私有仓库无 REST API(仅 UI) |
---
## 要求
- Python 3.8+
- 已安装并认证的 [`gh` CLI](https://cli.github.com/)(`gh auth login`),**或** 在环境中设置 `GITHUB_TOKEN`
- 对于 `--local` / `--from`(推送或克隆代码):你的常规 git 凭证必须设置好——要么是加载到 `ssh-agent` 中的 SSH 密钥(当 `gh config get git_protocol` 为 `ssh` 时),要么是 HTTPS 凭证助手(`gh auth setup-git` 会自动配置一个)。OAuth 令牌**不**用于 git 推送,因此工作流文件(`.github/workflows/*`)推送时无需 OAuth `workflow` 作用域。
- [`uv`](https://docs.astral.sh/uv/) 用于从源代码安装(推荐)
- `truffleHog` v3(可选——用于预检扫描器;自动从 PATH 检测,或通过 podman/docker 运行;如果两者都不可用,则回退到正则表达式)
---
## 安装
### 使用 uv 从源代码安装(推荐)```bash
git clone https://github.com/your-username/gh-safe-repo
cd gh-safe-repo
uv tool install .
这将把 gh-safe-repo 安装到 uv 的工具环境中,并将其添加到你的 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>
### 验证```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 参考```
gh-safe-repo create <owner/repo> [OPTIONS]
gh-safe-repo fix <owner/repo> [OPTIONS]
gh-safe-repo scan <path> [OPTIONS]
所有与GitHub交互的命令都需要使用 owner/repo 格式(例如 myuser/my-repo)。对于 create,会根据你已认证的GitHub账户验证所有者,以防止在多账户系统上出错。对于 fix,则需要目标仓库的管理员权限,从而允许你修复由组织或其他账户拥有且你具有管理员访问权限的仓库。
create — 创建新仓库单纯的 create(没有 --local/--from)会初始化仓库以使默认分支存在用于分支保护,然后删除自动生成的 README.md,使新仓库从干净状态开始。在配置中设置 auto_init = true 可以保留README。--local/--from 推送你自己的历史记录,且从不创建README。
fix — 审计并修复现有仓库scan — 本地秘密扫描| 选项 | 说明 |
|---|---|
--config [PATH] | 配置文件路径;单独的 --config 仅使用内置默认值 |
--debug | 显示扫描器详情 |
如果没有严重发现,退出代码为 0,如果发现严重问题则为 1。
--dry-run 精确显示 gh-safe-repo 将会执行的操作,而不做任何更改或API调用。在实际运行前使用它。与 --json 结合以获取机器可读的计划输出:```bash
gh-safe-repo create <owner/repo> --dry-run --json
gh-safe-repo fix <owner/repo> --dry-run --json
当 `--json` 激活时,计划将作为 JSON 对象写入 stdout,所有其他消息(进度、警告、“试运行”脚注)将写入 stderr,因此输出是干净的,适合管道或脚本处理。```
$ 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.
操作颜色:
| 操作 | 含义 |
|---|---|
ADD(绿色) | 正在应用的新设置 |
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` 仅包含计划中存在的类型。使用者应使用 `.get("delete", 0)` 等方法,而不是假设所有四个键都存在。
---
## 修复模式(审计现有仓库)
`fix` 将现有仓库的当前设置与安全默认值进行比较,并应用任何修正。不进行秘密扫描 — `fix` 纯粹与仓库设置有关。```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
修复模式:
UPDATE 表示已更改的设置,用 SKIP 表示已经处于期望值的设置(无操作检测——它从不发起会改变任何内容的 API 调用)--yes 跳过)仅应用实际更改——已经处于期望值的设置显示为 SKIP,并且不产生 API 调用。
--from)--from 将现有仓库镜像到一个带有安全默认设置的新仓库。它适用于私密和公开目的地:```bash
gh-safe-repo create <owner/repo> --from <owner/source>
gh-safe-repo create <owner/pub> --from <owner/priv> --public
**按顺序执行的操作:**
1. 你的 `github.com` 的 Git 凭据会首先被验证(当 `gh config get git_protocol` 为 `ssh` 时进行 SSH 探测;HTTPS 被认为是可信的),因此,在创建任何仓库之前,缺失密钥会快速失败。
2. 源仓库被克隆到本地(完整克隆,不使用 `--depth`,以便 truffleHog 可以遍历完整的提交历史)。
3. [预检安全扫描器](#pre-flight-security-scanner)在本地克隆上运行。
4. 你审查发现并确认(或中止)。
5. 创建一个新仓库(默认私有,或使用 `--public` 设为公开)。
6. 应用 Actions 权限和安全设置(Dependabot、秘密扫描、推送保护)。
7. 完整历史被镜像:`git clone --mirror` + `git push --mirror`。
8. 应用分支和标签保护(在代码推送之后,因此目标分支存在)。
如果扫描发现问题而你中止,则不会有任何代码被复制到 GitHub。
> **注意:** `--from` 对源和目标都使用 `owner/repo` 格式。
---
## 从本地目录创建仓库(`--local`)
`--local PATH` 是 `--from` 的本地到 GitHub 对应项。它创建一个新的 GitHub 仓库,并从本地 git 仓库推送代码。`PATH` 必须是一个已初始化的 git 仓库(`git init` 或克隆)。```bash
gh-safe-repo create <owner/repo> --local ~/projects/myapp
gh-safe-repo create <owner/repo> --local ~/projects/myapp --public
按顺序发生的事情:
github.com 的 git 凭据(当 gh config get git_protocol 为 ssh 时进行 SSH 探测;HTTPS 被信任),因此如果密钥缺失,会在创建任何仓库之前快速失败push --all --tags 推送完整历史(所有分支和标签)origin 添加到原始本地仓库,指向新的 GitHub URL,并配置当前分支的上游跟踪 — 这样 git push 和 git pull 立即生效,无需额外设置。--local 和 --from 都适用于私有和公开仓库。它们互斥。
使用本地默认分支(通过 git -C PATH symbolic-ref HEAD)来定位分支保护规则,因此保护会应用于正确的分支,即使它不是 main。
提示: 如果你想在不创建任何东西的情况下检查发现结果,请先运行
gh-safe-repo scan PATH。
检查器在本地运行,从不将代码发送到 GitHub。在任何推送之前独立使用它,或者它会作为 --from 和 --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
完整的 [pre_flight_scan] 配置同样适用:banned_strings、max_file_size_mb、trufflehog_mode 等。
gh-safe-repo 通过三步发现链自动选择最佳可用的扫描器:
trufflehog --version,确认为 v3 后使用。如果安装的是 v2 或无法识别的版本,则打印警告并回退至第 2 步。ghcr.io/trufflesecurity/trufflehog:latest)中运行 truffleHog,使用 podman run 或 docker run,以只读方式挂载扫描路径至相同的绝对路径,使得 JSON 输出路径与原生运行一致。所选扫描器会显示在“运行预检安全扫描...”标题以及计划表的 SCAN 条目中,例如:``` 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)
容器路径识别的环境变量:`CONTAINER_RUNTIME` 用于覆盖运行时选择(例如 `CONTAINER_RUNTIME=docker`),以及 `TRUFFLEHOG_IMAGE` 用于固定特定的镜像标签。
### 通过 podman 或 Docker 运行 truffleHog(无需本地安装)
无需手动设置。`gh-safe-repo` 会自动检测 podman 或 docker(上述步骤2),并使用正确的卷挂载在容器中运行 truffleHog。`CONTAINER_RUNTIME` 和 `TRUFFLEHOG_IMAGE` 环境变量会被遵循。
提供了一个 shell 包装脚本(`tools/trufflehog`)和一个用于构建固定本地镜像的 `Containerfile`,位于 [`tools/`](https://github.com/ariesq/gh-safe-repo/blob/master/tools/README.md) 中,适用于希望系统范围内使用基于容器的 truffleHog,或需要离线镜像的用户。
### 交互式审查```
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)。你必须显式输入y以继续。Y)。按回车键继续或输入n中止。输出中的机密信息会被编辑。电子邮件地址和TODO会显示匹配行。
默认跳过构建产物目录(node_modules、__pycache__、.venv、venv、dist、build)以保持扫描速度。在git仓库中,这种跳过是有条件的:在修剪目录之前,扫描器会运行git ls-files -- <dir>来检查其中是否有文件被跟踪。如果有,则正常扫描该目录。
这意味着已提交的node_modules或dist树——虽然不常见,但确实存在——不会被无声地遗漏。未提交的目录(通常情况)继续像之前一样被跳过。
当在克隆的源代码仓库中发现SKIP_DIRS子目录时,仍然会打印一条警告,因为它们的出现可能表明提交的内容比预期的多。
两个配置键可以让你抑制已知安全的发现,而无需禁用整个检查类别。
scan_exclude_paths —— 完全跳过文件或目录。值是以换行符/逗号分隔的正则表达式模式,与相对文件路径匹配。匹配的文件会被排除在所有检查之外:机密、电子邮件、TODO、大文件和AI上下文文件检测。相同的模式也会通过--exclude-paths传递给truffleHog,因此无论使用哪个扫描引擎,覆盖范围都是一致的。```ini
[pre_flight_scan]
scan_exclude_paths = docs/api.github.com.json tests/fixtures/
**`exclude_emails`** — 抑制针对特定地址或整个域名的邮件发现结果。值以换行符或逗号分隔,不区分大小写。以 `@` 开头的条目匹配该域名下的所有邮件地址;否则条目必须精确匹配完整地址。适用于工作目录和 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
当发现被禁止的字符串或AI上下文文件时,扫描器会输出一条可直接运行的`git filter-repo`命令,用于在重新运行前将这些内容从源代码仓库的历史记录中移除。
---
## 配置
`gh-safe-repo` 按以下顺序查找配置(优先匹配第一个):
1. **`--config PATH`** — 显式覆盖
2. **`./gh-safe-repo.ini`** — 当前工作目录
3. **`$XDG_CONFIG_HOME/gh-safe-repo/gh-safe-repo.ini`** — 当 `$XDG_CONFIG_HOME` 未设置时,默认为 `~/.config`
单独的 `--config`(不带路径)会完全跳过文件查找,仅使用内置默认值。
所有值都有安全的默认值 —— 无需配置文件即可开始使用。
一个带有完整注释的示例配置文件包含在仓库中,文件名为 `gh-safe-repo.ini.example`。将其复制以开始使用:```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.---
## GitHub 计划限制
某些功能仅根据仓库可见性和您的 GitHub 计划可用。
| Feature | Free + Public | Free + Private | Pro/Team + Private |
|---|:---:|:---:|:---:|
| Branch protection / Rulesets | Yes | No | Yes |
| Tag protection (Rulesets) | Yes | No | Yes |
| Dependabot alerts | Yes | No | Yes |
| Dependabot security updates | Yes | No | Yes |
| Secret scanning | Auto | No | Yes |
| Push protection | Yes | No | Yes |
| Private vulnerability reporting | Yes | Yes | Yes |
| Dependency graph | Auto | No | Yes |
`gh-safe-repo` 在运行时检测您的计划级别和仓库可见性。不可用的功能在计划输出中显示为 `SKIP`,并附有明确的原因——该工具永远不会静默失败。
---
## 工作原理```
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)
每一类设置都是一个自包含的插件类 (gh_safe_repo/plugins/)。每个插件:
Plan(Change 对象列表:ADD / UPDATE / DELETE / SKIP)这意味着审计模式和创建模式使用相同的计划/应用路径。唯一的区别在于,当前状态是从现有仓库获取还是假定为 GitHub 默认值。
API 调用按以下顺序解析令牌:
GITHUB_TOKEN 环境变量——允许你在不切换活动 gh 会话的情况下定位特定账户(也是在 CI 中唯一需要的凭据)gh auth token——由 gh auth login 设置的任何内容令牌作为 GH_TOKEN 传递给子进程 gh api 的子进程环境,并且从不记录。
Git 操作(--local / --from 的推送和克隆)默认使用你自己的 git 凭据——SSH 密钥或凭据助手——而不是 API 令牌。在两者都不可用的环境中(例如只有 GITHUB_TOKEN 的 CI),该工具会回退到通过 HTTPS 推送,并在 URL 中包含令牌;[git_transport] mode 配置设置控制此行为(请参阅配置参考)。包含令牌的 URL 永远不会写入你的仓库 .git/config,并且会从所有输出中移除。
所有 GitHub API 调用都通过 subprocess 使用 gh api。这使身份验证完全保留在 gh CLI 中——无需令牌管理代码,无需 OAuth 流程,无需固定 PyGithub 版本。JSON 请求正文通过 --input -(标准输入)传递,而不是 --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 .
参见 [`tests/README.md`](https://github.com/ariesq/gh-safe-repo/blob/master/tests/README.md) 了解测试文件描述、模拟约定以及如何添加新测试。
### 项目结构```
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/
有关模块映射、插件架构以及添加新设置的指南,请参见gh_safe_repo/README.md。
没有运行时依赖。所有内容均使用 Python 标准库(argparse、configparser、subprocess、json、re)。未经讨论,请勿添加第三方包。
pytest 是唯一的开发依赖,已在 pyproject.toml 中声明为 UV 原生的 [dependency-groups] 条目。
在设计过程中,我们研究了以下项目,它们影响了 gh-safe-repo 的架构。这些是不同的工具,具有不同的作用范围和用户模型——有关模式如何适应的详细技术说明,请参见 docs/LEARNINGS.md。
github/safe-settings — 一个组织级别的 GitHub 应用程序(Node.js/Probot),可从中央配置强制执行仓库设置。提供了插件架构模式(每个设置类别一个类,fetch → diff → apply)以及 mergeDeep 比较方法的来源。
repository-settings/app — 一个更简单的每个仓库变体的 safe-settings,也是 Node.js/Probot。为 Diffable 基础插件模式提供了更清晰的参考。
nicholasgasior/gh-repo-settings — 一个用 Go 编写的 CLI 扩展,具有 plan/apply 工作流。是 gh api 子进程包装器模式和 dry-run plan 输出设计的主要灵感来源。
| 选项 | 说明 |
|---|
--public | 创建为公开仓库(默认:私有) |
--local PATH | 从本地git仓库推送代码到新仓库。先运行预检扫描。与 --from 互斥。 |
--from OWNER/REPO | 从现有仓库镜像代码到新仓库。运行预检扫描。与 --local 互斥。 |
--yes / -y | 跳过确认提示并立即应用(用于脚本/批处理) |
--dry-run | 打印计划但不做任何更改 |
--json | 将计划以JSON格式输出到stdout而不是ANSI表格 |
--config [PATH] | 配置文件路径;单独的 --config 仅使用内置默认值 |
--debug | 打印每个API调用和响应 |
| 选项 | 说明 |
|---|
--yes / -y | 跳过确认提示并立即应用(用于脚本/批处理) |
--dry-run | 显示设置差异但不应用更改 |
--json | 将计划以JSON格式输出到stdout而不是ANSI表格 |
--config [PATH] | 配置文件路径;单独的 --config 仅使用内置默认值 |
--debug | 打印每个API调用和响应,以及解析后的仓库标识(id, full name, owner type) |
UPDATE(黄色) | 现有设置正在更改(审计模式) |
DELETE(红色) | 正在删除的设置 |
SKIP(暗色) | 无需操作——已达到所需值,或您的计划/可见性组合不支持此功能 |
| 类别 | 严重级别 | 示例 |
|---|
| 硬编码密钥 | 严重 | AWS 密钥(AKIA…)、GitHub 令牌(ghp_…、github_pat_…)、私钥、数据库 URL |
| 禁用字符串 | 严重 | 你配置的任何字面字符串(用户名、内部主机名、项目代号) |
| AI 上下文文件 | 严重 | CLAUDE.md、AGENTS.md、.cursorrules、copilot-instructions.md、.cursor/ —— 可能包含内部开发笔记;Git 历史可能比当前版本更敏感 |
| 电子邮件地址 | 警告 | 工作树和 Git 历史中任何 [email protected] 模式 |
| 大文件 | 警告 | 超过配置大小阈值的文件(默认:100 MB) |
| TODO/FIXME 注释 | 信息 | # TODO、# FIXME、# HACK、# XXX |