AriESQ/gh-safe-repo

GitHub: AriESQ/gh-safe-repo

一款 Python CLI 工具,用于一键创建具备安全默认配置的 GitHub 仓库,并支持审计修复现有仓库和预推送机密扫描。

Stars: 7 | Forks: 1

# gh-safe-repo 自动创建应用了安全默认设置的 GitHub 仓库。用一个命令替代创建后长达五分钟的设置检查清单。 ``` gh-safe-repo create ``` 分支保护、不可变标签、Dependabot、受限 Actions 权限、带推送保护的机密扫描,以及禁用的 wiki 和 projects —— 全部在你编写第一行代码前配置完毕。 gh-safe-repo 正处于密集开发阶段。它非常适合用于创建具有安全默认设置的新仓库。我正在努力完善 CLI 选项,以最大程度符合用户期望。在我正式发布版本并完善 CI/CD 之前,请预期会有破坏性变更。✌️ ## 目录 - [为什么做这个](#why) - [变更内容](#what-it-changes) - [环境要求](#requirements) - [安装](#installation) - [快速开始](#quick-start) - [CLI 参考](#cli-reference) - [空运行 / 计划输出](#dry-run--plan-output) - [修复模式(审计现有仓库)](#fix-mode-audit-existing-repos) - [镜像仓库 (`--from`)](#mirroring-repos---from) - [从本地目录创建仓库 (`--local`)](#creating-a-repo-from-a-local-directory---local) - [预飞行安全扫描器](#pre-flight-security-scanner) - [独立扫描](#standalone-scan) - [抑制误报](#suppressing-false-positives) - [配置](#configuration) - [GitHub 套餐限制](#github-plan-limitations) - [工作原理](#how-it-works) - [开发](#development) ## 为什么做这个 GitHub 的默认仓库设置针对可发现性和灵活性进行了优化,而非安全性。每个新仓库都默认包含: - 启用的 Wiki 和 Projects(即使未使用,也会增加攻击面) - 允许合并提交(历史记录杂乱,但这不是主要问题) - 无分支保护(任何有写入权限的人都可以直接推送到 `main`) - 无 Dependabot 警报 - GitHub Actions 拥有仓库的写入权限 - Actions 被允许批准拉取请求 手动修复所有这些问题每个仓库需要花费数分钟,而且很容易遗忘。`gh-safe-repo` 通过一次操作应用一组既定且实用的默认设置,并提供计划预览,让你在任何更改发生前确切知道会改变什么。 ## 变更内容 ### 仓库设置 | 设置 | GitHub 默认值 | 安全默认值 | 备注 | |---|---|---|---| | 可见性 | Public | **Private** | 传递 `--public` 以覆盖 | | Wiki | Enabled | **Disabled** | | | Projects | Enabled | **Disabled** | | | Issues | Enabled | Enabled | | | 合并时删除分支 | Off | Off | 在配置中设为 `true` 以自动清理 | | 允许合并提交 | On | On | 在配置中设为 `false` 以仅使用 squash | | 允许 Squash 合并 | On | On | | | 允许变基合并 | On | On | | ### GitHub Actions | 设置 | GitHub 默认值 | 安全默认值 | |---|---|---| | 允许的 actions | All | **Selected** (GitHub 拥有 + 已验证创建者;可自定义) | | 默认工作流权限 | Read/write | **Read-only** | | Actions 可以批准 PR | Yes | **No** | | 需要 SHA 固定 | No | **Yes** (工作流必须将 actions 固定到 commit SHA,而不是可变标签) | | Fork PR 批准策略 | GitHub 的新手首次贡献者 | **所有外部贡献者** — 要求 fork PR 工作流在运行 CI 之前获得批准。选项:仅限全新的 GitHub 账户(GitHub 默认)、仓库的首次贡献者或所有 fork PR(最安全) | ### 分支保护(公开仓库,或付费套餐上的任何仓库) | 规则 | 值 | |---|---| | 合并前需要拉取请求 | Yes | | 需要批准的审查 | 1 | | 推送时忽略旧的审查 | Yes | | 需要解决对话 | Yes | | 允许强制推送 | No | | 允许分支删除 | No | | 对管理员强制执行 | No (允许所有者工具推送) | ### 标签保护(公开仓库,或付费套餐上的任何仓库) | 规则 | 值 | |---|---| | 受保护的标签模式 | `*` (所有标签;可配置) | | 防止标签删除 | Yes | | 防止标签更新(重写) | Yes | | 管理员绕过 | Yes (与分支保护一致) | 标签保护仅使用 Rulesets API —— 没有“经典”标签保护的等效项。这仅适用于公开仓库或付费 GitHub 套餐(与分支保护的限制相同)。免费套餐的私有仓库将在计划输出中看到此项被跳过。 ### 安全 | 功能 | 行为 | |---|---| | Dependabot alerts | Enabled (公开仓库 / 付费套餐) | | Dependabot 安全更新 | Enabled (自动为有漏洞的依赖项打开 PR) | | 机密扫描 | 公开仓库上自动开启;在付费私有套餐上启用 | | 推送保护 | Enabled (阻止包含受支持机密的提交) | | 私有漏洞报告 | Enabled (允许安全研究人员私下报告) | | 依赖图 | 公开仓库上自动开启;私有仓库无 REST API (仅 UI) | ## 环境要求 - Python 3.8+ - 已安装并通过认证的 [`gh` CLI](https://cli.github.com/) (`gh auth login`),**或者**在你的环境中设置 `GITHUB_TOKEN` - 用于从源码安装的 [`uv`](https://docs.astral.sh/uv/) (推荐) - `truffleHog` v3 (可选 —— 由预飞行扫描器使用;从 PATH 自动检测,或通过 podman/docker 运行;如果两者都不可用,则回退到正则表达式) ## 安装 ### 使用 uv 从源码安装 (推荐) ``` 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 ``` ### 验证 ``` gh-safe-repo --help ``` ## 快速开始 ``` # 使用所有安全默认值创建私有 repo gh-safe-repo create # 预览将要发生的操作 — 不做任何更改 gh-safe-repo create --dry-run # 创建公共 repo(应用分支保护 + 安全扫描) gh-safe-repo create --public # 将现有 repo 镜像到新的私有 repo(带预扫描) gh-safe-repo create --from # 将私有 repo 镜像到新的公共 repo(带预扫描) gh-safe-repo create --from --public # 从本地目录创建 repo(带预扫描) gh-safe-repo create --local ~/projects/myapp # 同上,但设为公开(推送前应用分支保护) gh-safe-repo create --local ~/projects/myapp --public # 审计现有 repo 并应用任何缺失的安全默认值 gh-safe-repo fix # 审计但不做更改 gh-safe-repo fix --dry-run # 应用修复且无需确认提示(脚本/批处理使用) gh-safe-repo fix --yes # 在推送到任何位置前扫描本地 repo 的机密信息 gh-safe-repo scan . gh-safe-repo scan ~/projects/myapp ``` ## CLI 参考 ``` gh-safe-repo create [OPTIONS] gh-safe-repo fix [OPTIONS] gh-safe-repo scan [OPTIONS] ``` 所有与 GitHub 交互的命令都需要 `owner/repo` 格式(例如 `myuser/my-repo`。系统会根据你认证的 GitHub 账户验证所有者,以防止在多账户系统上出错。 ### `create` — 创建新仓库 | 选项 | 描述 | |---|---| | `--public` | 创建为公开仓库 (默认: 私有) | | `--local PATH` | 将本地目录中的代码推送到新仓库。首先运行预飞行扫描。与 `--from` 互斥。 | | `--from OWNER/REPO` | 将现有仓库中的代码镜像到新仓库。运行预飞行扫描。与 `--local` 互斥。 | | `--yes` / `-y` | 跳过确认提示并立即应用 (用于脚本/批处理) | | `--dry-run` | 打印计划而不进行任何更改 | | `--json` | 将计划作为 JSON 发送到 stdout,而不是 ANSI 表格 | | `--config PATH` | 配置文件路径 (默认: `./gh-safe-repo.ini` 或 `~/.config/gh-safe-repo/gh-safe-repo.ini`) | | `--debug` | 打印每个 API 调用和响应 | ### `fix` — 审计并修复现有仓库 | 选项 | 描述 | |---|---| | `--yes` / `-y` | 跳过确认提示并立即应用 (用于脚本/批处理) | | `--dry-run` | 显示设置差异而不应用更改 | | `--json` | 将计划作为 JSON 发送到 stdout,而不是 ANSI 表格 | | `--config PATH` | 配置文件路径 (默认: `./gh-safe-repo.ini` 或 `~/.config/gh-safe-repo/gh-safe-repo.ini`) | | `--debug` | 打印每个 API 调用和响应 | ### `scan` — 本地机密扫描 | 选项 | 描述 | |---|---| | `--config PATH` | 配置文件路径 (默认: `./gh-safe-repo.ini` 或 `~/.config/gh-safe-repo/gh-safe-repo.ini`) | | `--debug` | 显示扫描器详细信息 | 如果没有关键发现,退出代码为 `0`,如果发现关键问题则为 `1`。 ## 空运行 / 计划输出 `--dry-run` 准确显示 `gh-safe-repo` 将执行的操作,而不进行任何更改或 API 调用。在正式运行之前使用它。结合 `--json` 获取机器可读的计划输出: ``` gh-safe-repo create --dry-run --json gh-safe-repo fix --dry-run --json ``` 当 `--json` 处于活动状态时,计划将作为 JSON 对象写入 stdout,所有其他消息(进度、警告、“Dry run”页脚)都会发送到 stderr,因此输出对于管道或脚本来说是干净的。 ``` $ gh-safe-repo create --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` (绿色) | 正在应用的新设置 | | `UPDATE` (黄色) | 正在更改的现有设置 (审计模式) | | `DELETE` (红色) | 正在移除的设置 | | `SKIP` (暗淡) | 功能在你的套餐/可见性组合下不可用 | **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` 纯粹关于仓库设置。 ``` # 查看不合规项 gh-safe-repo fix --dry-run # 应用缺失的安全默认值 gh-safe-repo fix # 应用且无需确认提示(脚本/批处理使用) gh-safe-repo fix --yes ``` 修复模式: 1. 通过 GitHub API 获取每个设置的当前值 2. 与所需的安全默认值进行比较 3. 显示包含 `UPDATE`(针对已更改设置)和 `SKIP`(针对已处于所需值的设置)的计划表(空操作检测 —— 它从不进行没有任何更改的 API 调用) 4. 在应用前提示确认 (使用 `--yes` 跳过) 已经正确的设置会被静默跳过。仅显示并应用真正的更改。 ## 镜像仓库 (`--from`) `--from` 将现有仓库镜像到具有安全默认值的新仓库。它适用于私有和公开目标: ``` # 镜像到新的私有 repo(默认) gh-safe-repo create --from # 将私有 repo 镜像到新的公共 repo(风险最高的操作 — 详尽扫描) gh-safe-repo create --from --public ``` **按顺序发生的事情:** 1. 源仓库在本地克隆 (完整克隆,无 `--depth`,以便 truffleHog 可以遍历完整的提交历史) 2. [预飞行安全扫描器](#pre-flight-security-scanner) 在本地克隆上运行 3. 你查看发现并确认 (或中止) 4. 创建一个新仓库 (默认为私有,或使用 `--public` 公开) 5. 应用安全默认值 (分支保护、安全扫描等) 6. 镜像完整历史:`git clone --mirror` + `git push --mirror` 7. 配置 Dependabot 和机密扫描 如果扫描发现问题并且你中止,则代码永远不会被复制到 GitHub。 ## 从本地目录创建仓库 (`--local`) `--local PATH` 是 `--from` 的本地到 GitHub 对应项。它创建一个新的 GitHub 仓库并从你机器上的目录推送代码。 ``` gh-safe-repo create --local ~/projects/myapp gh-safe-repo create --local ~/projects/myapp --public ``` **按顺序发生的事情:** 1. [预飞行安全扫描器](#pre-flight-security-scanner) 直接在本地目录上运行 (无需克隆) 2. 你查看发现并确认 (或中止) 3. 使用应用的安全默认值创建新仓库 4. **在任何代码推送之前**应用分支保护 (当 `--public` 时) 5. 推送代码: - 如果 `PATH` 是 git 仓库:完整历史在本地克隆并使用 `push --all --tags` 推送 (所有分支和标签) - 如果 `PATH` 是普通目录:文件在全新仓库中暂存并作为初始提交推送 - 如果 `PATH` 是空目录:不推送任何内容 (静默跳过) 6. 如果 `PATH` 是 git 仓库,则将 `origin` 添加到指向新 GitHub URL 的**原始**本地仓库,并配置当前分支的上游跟踪 —— 因此 `git push` 和 `git pull` 无需额外设置即可立即工作。 `--local` 和 `--from` 均适用于私有和公开仓库。它们互斥。 当 `PATH` 是 git 仓库时,本地默认分支 (通过 `git -C PATH symbolic-ref HEAD`) 用于定位分支保护规则,因此即使不是 `main`,保护也会落在正确的分支上。 ## 预飞行安全扫描器 扫描器在本地运行,从不向 GitHub 发送代码。在每次推送前单独使用它,或者它会作为 `--from` 和 `--local` 工作流程的一部分自动运行。 ### 独立扫描 ``` # 扫描当前目录 gh-safe-repo scan . # 扫描指定路径 gh-safe-repo scan ~/projects/myapp ``` 如果没有关键发现,退出代码为 `0`,如果发现关键问题则为 `1` —— 因此它可以与其他命令清晰地组合: ``` gh-safe-repo scan . && git push ``` 完整的 `[pre_scan]` 配置适用:`banned_strings`、`max_file_size_mb`、`trufflehog_mode` 等。 ### 它检测什么 | 类别 | 严重性 | 示例 | |---|---|---| | 硬编码机密 | Critical | AWS 密钥 (`AKIA…`)、GitHub 令牌 (`ghp_…`、`github_pat_…`)、私钥、数据库 URL | | 禁止的字符串 | Critical | 你配置的任何文字字符串 (用户名、内部主机名、代号) | | AI 上下文文件 | Critical | `CLAUDE.md`, `AGENTS.md`, `.cursorrules`, `copilot-instructions.md`, `.cursor/` — 可能包含内部开发说明;git 历史可能比当前版本更敏感 | | 电子邮件地址 | Warning | 工作树和 git 历史中的任何 `user@domain.tld` 模式 | | 大文件 | Warning | 超过配置大小阈值 (默认: 100 MB) 的文件 | | TODO/FIXME 注释 | Info | `# TODO`, `# FIXME`, `# HACK`, `# XXX` | ### 扫描器引擎 `gh-safe-repo` 使用三步发现链自动选择最佳可用扫描器: 1. **PATH 上的 truffleHog v3** — 运行 `trufflehog --version`,验证它是 v3,并使用它。v2 安装或无法识别的版本会打印警告并回退到第 2 步。 2. **podman 或 docker** — 如果未找到原生 truffleHog,扫描器将在容器 (`ghcr.io/trufflesecurity/trufflehog:latest`) 中使用 `podman run` 或 `docker run` 运行 truffleHog,并以只读方式挂载扫描路径到相同的绝对路径,以便 JSON 输出路径与原生运行相同。 3. **正则回退** — 如果原生安装和容器运行时都不可用,将打印警告并运行正则扫描器。它也总是在 truffleHog 之外运行以检查电子邮件和 TODO,并捕获 truffleHog 故意跳过的单独 key-ID 模式 (truffleHog 需要凭证对的两半,例如 AWS Key ID *和* Secret Access Key,然后才会标记发现)。 选定的扫描器显示在“Running pre-flight security scan...”标题和计划表的 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` 环境变量。 [`tools/`](tools/README.md) 中提供了 shell 包装器 (`tools/trufflehog`) 和用于构建固定本地镜像的 `Containerfile`,供希望在整个系统范围内使用基于容器的 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="alice@example.com" 1 critical finding, 1 warning. Critical findings detected. Continue anyway? [y/N]: ``` - **关键发现:** 默认为中止 (`N`)。你必须明确输入 `y` 才能继续。 - **仅警告:** 默认为继续 (`Y`)。按 Enter 继续 或输入 `n` 中止。 - **无发现:** 扫描静默完成,工作流程继续。 机密在输出中被编辑。电子邮件地址和 TODO 显示匹配的行。 ### 扫描覆盖范围 构建产物目录 (`node_modules`, `__pycache__`, `.venv`, `venv`, `dist`, `build`) 默认被跳过以保持扫描快速。在 git 仓库中,此跳过是有条件的:在修剪目录之前,扫描器运行 `git ls-files -- ` 以检查内部是否有任何文件被跟踪。如果是,则正常扫描目录。 这意味着已提交的 `node_modules` 或 `dist` 树 —— 不常见,但会发生 —— 不会被静默遗漏。未提交的目录(正常情况)继续像以前一样被跳过。 当在克隆的源仓库中发现 SKIP_DIRS 子目录时,仍会打印警告,因为它们的存在可能表明提交的内容比预期的多。 ### 抑制误报 两个配置键允许你抑制已知安全的发现,而无需禁用整个检查类别。 **`scan_exclude_paths`** — 完全跳过文件或目录。值是与相对文件路径匹配的换行/逗号分隔正则表达式模式。匹配的文件从每个检查中排除:机密、电子邮件、TODO、大文件和 AI 上下文文件检测。相同的模式也通过 `--exclude-paths` 传递给 truffleHog,因此无论哪个扫描器引擎处于活动状态,覆盖范围都是一致的。 ``` [pre_flight_scan] # 排除 GitHub API spec(示例 token)和所有测试 fixtures scan_exclude_paths = docs/api\.github\.com\.json tests/fixtures/ ``` **`exclude_emails`** — 抑制特定地址或整个域的电子邮件发现。值是换行/逗号分隔的,不区分大小写。以 `@` 开头的条目匹配该域的所有电子邮件;否则,条目必须完全匹配完整地址。适用于工作树和 git 历史发现。 ``` [pre_flight_scan] # 屏蔽机器人地址和占位符域名 exclude_emails = action@github.com, noreply@github.com, @example.com ``` ### 扫描器配置 ``` [pre_flight_scan] scan_for_secrets = true scan_for_emails = true scan_for_todos = true max_file_size_mb = 100 # 扫描 git 历史记录中的电子邮件地址(需要 scan_for_emails = true) # scan_email_history = true # 扫描器选择:auto | native | docker | off # auto — 尝试原生 truffleHog,回退到容器,然后是 regex(默认) # native — 仅原生 truffleHog;无容器回退 # docker — 仅容器;跳过原生 PATH 检查 # off — 仅 regex 扫描器,不尝试 truffleHog # trufflehog_mode = auto # 将 AI 上下文文件(CLAUDE.md, AGENTS.md, .cursorrules 等)标记为关键发现。 # 其 git 历史记录可能包含比当前版本更敏感的内容。 # warn_ai_context_files = true # 标记为关键发现的字面字符串(不区分大小写)。 # 逗号分隔或每行一个(续行必须缩进)。 # banned_strings = secret # password # credential # 从所有扫描检查中排除文件/目录(regex 模式,逗号/换行分隔)。 # 相同的模式通过 --exclude-paths 传递给 truffleHog。 # scan_exclude_paths = docs/api\.github\.com\.json # tests/fixtures/ # 屏蔽特定地址或整个域名的电子邮件发现(不区分大小写)。 # 以 @ 开头的条目匹配该域下的所有电子邮件;否则为精确地址匹配。 # exclude_emails = action@github.com, noreply@github.com, @example.com ``` 当发现禁止的字符串或 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` 所有值都有安全默认值 —— 开始使用不需要配置文件。 仓库中包含一个完全注释的示例配置 `gh-safe-repo.ini.example`。复制它以开始: ``` # 用户级配置 (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" # 或项目级配置(当前目录) cp gh-safe-repo.ini.example ./gh-safe-repo.ini ``` ### 完整配置参考 ``` [repo] # 新 repo 是否默认为私有 private = true # 禁用未使用时会造成混乱的功能 has_wiki = false has_projects = false has_issues = true # 合并后自动删除 head 分支(默认:off,与 GitHub 一致) delete_branch_on_merge = false # 合并策略(默认全部启用,与 GitHub 一致) # 设置 allow_merge_commit = false 以实现仅 squash 工作流 allow_squash_merge = true allow_merge_commit = true allow_rebase_merge = true # 不要使用 README 初始化 — 保持远程为空以便无缝推送 auto_init = false [actions] # 允许运行哪些 actions:all | local_only | selected allowed_actions = selected # 当 allowed_actions = selected 时,控制允许哪些外部 actions: github_owned_allowed = true # actions maintained by GitHub (e.g. actions/checkout) verified_allowed = true # actions from Marketplace verified creators # patterns_allowed = myorg/* # 逗号分隔的允许列表(支持通配符) # 最小权限原则:默认只读 # 选项:read | write default_workflow_permissions = read # 防止 Actions 自我批准 pull requests can_approve_pull_request_reviews = false # 要求 workflows 将 actions 固定到特定的 commit SHA 而不是可变 tag sha_pinning_required = true [branch_protection] # 应用于任何付费计划的公共 repo,以及付费计划的私有 repo。 # 要保护的分支 protected_branch = main # 合并前需要 pull request require_pull_request = true # 所需的批准数量 required_approving_reviews = 1 # 推送新 commits 时取消现有的批准 dismiss_stale_reviews = true # 合并前要求解决所有审查评论 require_conversation_resolution = true # 不对管理员强制执行规则 # false = repo 所有者仍可直接推送(--from mirror 工作流需要) enforce_admins = false # 阻止强制推送 allow_force_pushes = false # 阻止分支删除 allow_deletions = false # 使用 Rulesets API 而非经典分支保护 # 规则相同,但支持绕过参与者,且是现代 GitHub API # use_rulesets = false [tag_protection] # 通过 Rulesets API 实现不可变 tags。 # 仅适用于公共 repo 或付费 GitHub 计划(与分支保护限制相同)。 # 要保护的 tags 的 Glob 模式 — 逗号分隔。 protected_tags = * # 防止删除匹配的 tags (git tag -d / git push --delete) prevent_tag_deletion = true # 防止重写匹配的 tags (git tag -f / force-push) prevent_tag_update = true [security] # 启用 Dependabot 漏洞警报 enable_dependabot_alerts = true # 自动打开 PR 以修复易受攻击的依赖项 enable_dependabot_security_updates = true # 允许安全研究人员私下报告漏洞 enable_private_vulnerability_reporting = true # 阻止包含受支持机密的 commits enable_secret_scanning_push_protection = true # 注意:以下功能没有 REST API,必须通过 UI 或 dependabot.yml 配置: # - 分组安全更新:使用 dependabot.yml groups 配合 applies-to: security-updates # - 自动依赖提交:通过 repo 设置 UI 启用 # - 依赖图:公共 repo 自动启用;私有 repo 通过 UI 启用 [pre_flight_scan] scan_for_secrets = true scan_for_emails = true scan_for_todos = true # 标记超过此阈值的文件 max_file_size_mb = 100 # 扫描 git 历史记录中的电子邮件地址(需要 scan_for_emails = true) # scan_email_history = true # 扫描器选择:auto | native | docker | off # auto = 尝试原生 truffleHog,回退到容器,然后是 regex # native = 仅原生 PATH # docker = 仅容器 # off = 仅 regex # trufflehog_mode = auto # 将 AI 上下文文件(CLAUDE.md, AGENTS.md, .cursorrules 等)标记为关键发现。 # warn_ai_context_files = true # 标记为关键发现的字面字符串(不区分大小写)。 # 逗号分隔,或每行一个并使用续行缩进。 # banned_strings = secret # password # credential # 从所有扫描检查中排除文件/目录(regex 模式,逗号/换行分隔)。 # 传递给 truffleHog via --exclude-paths 并应用于 regex 遍历。 # scan_exclude_paths = docs/api\.github\.com\.json # tests/fixtures/ # 屏蔽特定地址或整个域名的电子邮件发现(不区分大小写)。 # 以 @ 开头的条目匹配该域下的所有电子邮件;否则为精确地址匹配。 # exclude_emails = action@github.com, noreply@github.com, @example.com ``` ## GitHub 套餐限制 某些功能仅根据仓库可见性和你的 GitHub 套餐可用。 | 功能 | 免费 + 公开 | 免费 + 私有 | 专业版/团队 + 私有 | |---|:---:|:---:|:---:| | 分支保护 / Rulesets | Yes | No | Yes | | 标签保护 | Yes | No | Yes | | Dependabot alerts | Yes | No | Yes | | Dependabot 安全更新 | Yes | No | Yes | | 机密扫描 | Auto | No | Yes | | 推送保护 | Yes | No | Yes | | 私有漏洞报告 | Yes | Yes | Yes | | 依赖图 | Auto | No | Yes | `gh-safe-repo` 在运行时检测你的套餐级别和仓库可见性。不可用的功能在计划输出中显示为 `SKIP`,并附带明确的原因 —— 该工具从不静默失败。 ## 工作原理 ``` gh-safe-repo create │ ├─ Parse owner/repo, validate owner matches authenticated user ├─ 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 → classic or Rulesets API │ ├─ 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 ├─ PUT /repos/{owner}/{repo}/branches/main/protection │ or POST /repos/{owner}/{repo}/rulesets (if use_rulesets = true) ├─ 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 + git push --all --tags (if --local, git repo) or git init + add -A + commit + push (if --local, plain dir) ``` ### 插件架构 每个设置类别都是一个自包含的插件类 (`gh_safe_repo/plugins/`)。每个插件: 1. 通过 GitHub API 获取当前状态 2. 与来自配置的所需状态进行比较 3. 返回一个 `Plan` (`Change` 对象列表: ADD / UPDATE / DELETE / SKIP) 4. 仅应用真正的更改 —— 空操作不进行 API 调用 这意味着审计模式和创建模式使用相同的计划/应用路径。唯一的区别是从现有仓库获取当前状态还是假定为 GitHub 默认值。 ### 认证 1. `gh auth token` — 首选;使用 `gh auth login` 设置的任何内容 2. `GITHUB_TOKEN` 环境变量 — CI/CD 回退 3. 如果两者都不可用则报错 令牌作为 `GH_TOKEN` 在子进程环境中传递给子 `gh api` 进程,并且从不被记录。 ### API 方法 所有 GitHub API 调用都通过 `subprocess` 经过 `gh api`。这使得认证完全保留在 `gh` CLI 中 —— 无令牌管理代码,无 OAuth 流程,无 PyGithub 版本固定。JSON 请求体通过 `--input -` (stdin) 传递,而不是 `--field` 标志。 ## 开发 ``` # Clone 并设置 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 --dry-run # 全局安装(获取当前源代码) uv tool install . ``` 有关测试文件描述、模拟约定以及如何添加新测试,请参阅 [`tests/README.md`](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`](gh_safe_repo/README.md)。 ### 依赖策略 **没有运行时依赖**。一切都使用 Python 标准库 (`argparse`, `configparser`, `subprocess`, `json`, `re`)。未经讨论,不要添加第三方包。 `pytest` 是唯一的开发依赖项,在 `pyproject.toml` 中声明为 UV 原生 `[dependency-groups]` 条目。 ## 先前艺术 这些项目在设计期间进行了研究,并影响了 `gh-safe-repo` 的架构。它们是具有不同范围和用户模型的独特工具 —— 有关如何调整模式的详细技术说明,请参阅 [docs/LEARNINGS.md](docs/LEARNINGS.md)。 - **[github/safe-settings](https://github.com/github/safe-settings)** — 组织级 GitHub App (Node.js/Probot),从中央配置强制执行仓库设置。插件架构模式(每个设置类别一个类,获取 → 比较 → 应用)和 `mergeDeep` 比较方法的来源。 - **[repository-settings/app](https://github.com/repository-settings/app)** — safe-settings 的更简单的单仓库变体,也是 Node.js/Probot。为 `Diffable` 基础插件模式提供了更清晰的参考。 - **[nicholasgasior/gh-repo-settings](https://github.com/nicholasgasior/gh-repo-settings)** — 用 Go 编写的 CLI 扩展,具有 `plan`/`apply` 工作流程。`gh api` 子进程包装器模式和空运行计划输出设计的主要灵感来源。
标签:CCS 2025, CI/CD安全, Dependabot, DevOps工具, DevSecOps, GitHub Actions, Golang-esque CLI, Llama, Python, SAST, Secrets Detection, StruQ, 上游代理, 代码仓库管理, 分支保护, 安全合规, 无后门, 盲注攻击, 网络代理, 自动化配置, 自动笔记, 请求拦截, 软件开发工具包, 逆向工具, 防御性安全, 预提交扫描, 默认安全