26zl/repo-harden
GitHub: 26zl/repo-harden
repo-harden 是一款零基础设施的多平台仓库安全审计与可逆加固工具,通过单个二进制文件即可扫描 GitHub/GitLab/Gitea/Forgejo 仓库安全态势并一键应用安全基线。
Stars: 1 | Forks: 0
# repo-harden
[](https://github.com/26zl/repo-harden/actions/workflows/ci.yml) [](https://pkg.go.dev/github.com/26zl/repo-harden)  [](LICENSE)
```
_ _
_ _ ___ _ __ ___ ___| |_ __ _ _ _ __| |___ _ _
| '_/ -_) '_ \/ _ \___| ' \/ _' | '_/ _' / -_) ' \
|_| \___| .__/\___/ |_||_\__,_|_| \__,_\___|_||_|
|_|
```
## 它的功能
三件事,无需基础设施 —— 只需一个本地二进制文件和一个 token:
- **审计(只读,多平台)。** 根据安全基线扫描您的仓库并获取安全态势评分。在 **GitHub** 上提供完整目录(50 多项检查);在 **GitLab, Gitea 和 Forgejo** 上提供可移植的子集。输出格式支持表格、JSON、Markdown 或 SARIF。
- **加固与还原(GitHub)。** 一键跨所有符合条件的仓库应用免费安全基线 —— 分支保护、只读 `GITHUB_TOKEN`、Dependabot、secret/code scanning。绑定到主机和账户的状态记录会追踪已应用、待处理或未明确的变更,以便 `revert` 能够安全地恢复已验证的更改。除非您主动选择,否则默认会跳过 Fork 和已归档的仓库。8 项可自动修复的控制措施支持还原。
- **Actions 管理(GitHub)。** 当您达到免费额度限制时,可以针对单个仓库或跨符合条件的仓库批量启用/禁用 Actions workflows,并保存状态以便日后恢复。
无需 GitHub App,无需组织管理员配置仓库,无需 Terraform,无需长期访问权限。
## 快速开始
```
# 安装
go install github.com/26zl/repo-harden/cmd/repo-harden@latest
# 在运行 GitHub API 命令之前进行身份验证(也支持 `GITHUB_TOKEN`)
gh auth login
# 查看符合条件的 repo 的状态(只读)— 也适用于 GitLab/Gitea/Forgejo
repo-harden audit # every repo your token can reach
repo-harden audit --repo me/app,me/lib # just these — skips the full scan, much faster
repo-harden audit --provider gitlab
# 预览 GitHub 修复、应用修复、撤销修复
repo-harden harden --dry-run
repo-harden harden
repo-harden revert
```
## 命令
**安全审计与加固**
| 命令 | 功能描述 |
| --- | --- |
| `audit` | 只读的安全态势扫描。通过 `--provider` 支持多平台。支持 `--format table\|json\|markdown\|sarif`,以及用于 CI 的 `--exit-code`。 |
| `harden` | 应用可自动修复的基线控制措施(共 8 项)并首先保存还原状态。仅限 GitHub。支持 `--dry-run`,`--only`/`--skip`。 |
| `revert` | 从绑定到主机/账户的恢复状态中还原已验证的更改。仅限 GitHub。 |
| `controls` | 列出每一项基线控制措施,以及它们是否可自动修复和可还原。离线运行,无需 token。 |
| `version` / `help` | 打印版本和构建信息 / 显示用法。离线运行,无需 token。 |
**GitHub Actions 管理**
| 命令 | 功能描述 |
| --- | --- |
| `list` / `status` | 列出 workflows / 显示符合条件的仓库中按状态划分的计数。 |
| `disable-all` / `enable-all` | 禁用符合条件的仓库中的所有活动 workflows(并保存状态) / 根据保存的状态重新启用。 |
| `enable-all-disabled` | 重新启用所有当前被禁用的 workflow(无需状态文件)。 |
| `disable-repo` / `enable-repo` | 切换单个 `owner/repo` 中的所有 workflow。无状态 —— `disable-repo` 通过 `enable-repo` 撤销,而不是 `enable-all`。 |
## 多平台审计
只读的 `audit` 可以在 GitHub 之外运行 —— 使用 `--provider` 将其指向另一个代码托管平台:
| Provider | 审计 | 加固 / Actions |
| --- | :---: | :---: |
| GitHub / GHES | ✅ 完整目录 | ✅ |
| GitLab | ✅ 可移植子集 | — |
| Gitea / Forgejo | ✅ 可移植子集 | — |
```
repo-harden audit --provider gitlab # uses GITLAB_TOKEN
repo-harden audit --provider gitea --host git.example.com # uses GITEA_TOKEN
```
`harden`/`revert` 和 Actions 命令在设计上仅限 GitHub 使用:分支保护可以跨平台移植,但高价值的扫描控制措施是 GitHub 专有的(或属于 GitLab 的付费层级),因此跨平台的 `harden` 基本上形同虚设。`audit` 提供了至关重要的跨平台可见性。
## 审计检查内容
这是一个**尽力而为的基线**,而不是详尽的安全审查(参见[尚未覆盖的内容](#not-yet-covered))。在 GitHub 上它会运行 50 多项检查;受限于许可证或无法访问的功能会被报告为 `skipped`,而不是进行猜测。输出内容包含一个基于严重性加权的验证百分比以及安全态势评分。当无法验证的检查必须导致 CI 失败时,请使用 `--fail-on-skipped`。
**`harden` 可自动修复的内容(8 项可还原的控制措施):** Dependabot 告警 + 安全更新 · 只读 `GITHUB_TOKEN`(且禁止批准 PR) · 默认分支规则集(要求 PR 审查、解决对话、禁止 force-push、线性历史) · 将 Actions 设置为选定的 GitHub 官方及已验证的 actions(这会清除任何自定义的允许列表模式 —— 审计会首先标记它们以供人工审查,而 `revert` 会将其恢复) · secret scanning + push protection · CodeQL 默认设置 · 私密漏洞报告。
**只读审计还涵盖(示例):** 分支保护深度(审查人数、状态检查、签名提交)、规则集绕过角色、**仅评估(dry-run)的规则集**(不执行任何强制措施)、**冲突的 code-scanning 设置**(默认设置与高级 workflow 之间)、**每个 workflow 的 GITHUB_TOKEN 权限**(最小权限原则)、Actions SHA 固定策略、账户及组织的 2FA、**社区健康文件**(issue/PR 模板、行为准则、贡献指南)、外部协作者、合并方法与 fork 策略、公开 wiki 的攻击面、协作者与管理员的清理状况、webhook TLS 配置/过期检查、部署密钥、environments、fork-PR 批准、公开暴露面、SBOM/依赖清单,以及组织级别的 Actions/token/secret/webhook 策略。
两项基线控制措施 —— `SECURITY.md` 和 `CODEOWNERS` —— 仅作报告使用:会被 `audit` 标记并被 `controls` 列出,但绝对不会被自动修改。
### 尚未覆盖的内容
已知的差距(欢迎贡献):dependency-review 强制执行、merge queues、针对要求的状态检查和 code-owner 审查的更深层规则集验证、artifact/SBOM 证明审计、Dependabot 私有注册表 secret、自托管 runner 策略,以及 webhook/environment 的 secret 安全维护。
## 可逆性与状态
在应用任何更改之前,`harden` 会将先前的值记录到:
```
$REPO_HARDEN_STATE_DIR/harden-state.json # if REPO_HARDEN_STATE_DIR is set
~/.repo-harden/harden-state.json # default
```
`revert` 会读取此文件并恢复被记录为已应用的更改。它会首先重新检测每一项实时设置,包括标记为 `applied` 的条目,并拒绝覆盖自 `harden` 执行以来已发生更改的设置。如果 API 调用失败且状态不明确,该条目将保持为 `pending`/`unknown`;已经合规的控制措施绝不会被记录。
状态文件已进行版本控制,并与 GitHub 主机和经过身份验证的账户绑定,因此未绑定的遗留文件以及跨主机或跨账户的重放请求都会被拒绝。
Actions 批量禁用使用一个独立的状态文件:
```
$REPO_HARDEN_STATE_DIR/enabled-workflows.json
~/.repo-harden/enabled-workflows.json
```
使用 `--state-file ` 可以覆盖您正在运行的命令的状态路径。请为每个命令系列提供各自的路径:`harden`/`revert` 和 Actions 命令使用不同的文件格式,因此将两者指向同一个 `--state-file` 会被拒绝,而不是静默地相互覆盖。
## CI 用法
```
repo-harden audit --exit-code # fail the job on any gap or error
repo-harden audit --exit-code --fail-on-skipped # strict: also fail if a check is unverifiable
repo-harden audit --format sarif > out.sarif # for GitHub code-scanning ingestion
```
## Flags
| Flag | 描述 |
| --- | --- |
| `--provider ` | `github`(默认),`gitlab`,`gitea`,`forgejo`(用于审计) |
| `--host ` | Provider 主机(GHES, GitLab, Gitea/Forgejo);接受 web 根目录或 API URL。Gitea/Forgejo 默认为 `http://localhost:3000` |
| `--token ` | Provider token(不推荐 —— 在 `ps`/shell 历史记录中可见;建议使用环境变量、`gh auth` 或 `--token-stdin`) |
| `--token-stdin` | 从 stdin 读取 provider token |
| `--dry-run` | 执行只读检测并打印预期的变更;仍会发生 API 读取调用 |
| `--owner ` | 仅处理由此用户/组织拥有的仓库 |
| `--repo ` | 仅限这些仓库(以逗号分隔);直接获取它们并跳过完整的账户扫描。Owner/admin/fork/archive 过滤器仍然适用。 |
| `--admin-only` | 仅包含您的 token 具有管理员权限的仓库 |
| `--only ` / `--skip ` | 运行 / 跳过特定的控制措施(以逗号分隔的键) |
| `--format ` | `table`(默认),`json`,`markdown`,`sarif` |
| `--all` | 审计表格默认仅显示差距/错误;`--all` 显示每一项检查(包括合规/跳过的检查) |
| `--json` | `list`、`status` 和 `audit` 的 JSON 输出快捷方式 |
| `--exit-code` | 当 `audit` 发现差距或错误时以非零状态退出 |
| `--fail-on-skipped` | 当任何审计检查被跳过/无法验证时以非零状态退出 |
| `--color ` / `--no-color` | `auto`(默认),`always`,`never`;支持 `NO_COLOR` |
| `--concurrency ` | 并行 API 调用(默认:8) |
| `--include-forks` / `--include-archived` | 包含 fork 的 / 已归档的仓库(默认跳过) |
| `--include-dynamic` | 包含默认被跳过的动态 Actions workflows |
| `--org-audit` | 包含 GitHub 组织级别的审计检查(默认开启;使用 `--org-audit=false` 禁用) |
| `--stale-days ` | 失效仓库的阈值(默认:180) |
| `--state-file ` | 覆盖默认的状态文件路径 |
| `--show-identifiers` | 在审计输出中包含 secret/CI 变量名、协作者用户名和部署密钥标题(默认隐藏) |
## 环境要求与安装
- Go 1.25.11+(`go.mod` 工具链锁定版本;在默认的 `GOTOOLCHAIN=auto` 下,会自动获取合适的工具链)
- 目标代码托管平台的 token:已登录 [`gh`](https://cli.github.com/)(`gh auth login`)或配置了 `GITHUB_TOKEN`;针对其他 provider 则需要 `GITLAB_TOKEN` / `GITEA_TOKEN` / `FORGEJO_TOKEN`
请使用满足您所运行命令要求的、权限最小的 token:
| 操作 | 所需权限 |
| --- | --- |
| GitHub 仓库审计 | 仓库元数据以及对正在审计的安全/设置端点的读取权限。无法访问的检查将被标为 `skipped`;当需要完全验证时,请将 CI 与 `--fail-on-skipped` 结合使用。 |
| GitHub 组织审计 | 组织读取权限;仅限管理员策略、成员 2FA、secret 和 webhook 端点需要相应的组织所有者/管理员可见性。 |
| `harden` / `revert` | 仓库管理写入权限,以及对选定的 Actions/code-security 设置的写入权限。 |
| Actions 启用/禁用命令 | 仓库 Actions 的写入权限。 |
| GitLab 审计 | 具有对选定项目及受保护/安全端点的 API 读取权限的 token。 |
| Gitea / Forgejo 审计 | 仓库读取权限;仅限管理员的端点需要仓库管理的可见性。 |
经典的 GitHub PAT 通常对私有仓库使用 `repo` 作用域,仅在选定的组织检查有要求时才使用 `read:org`/`admin:org`。建议优先使用限定于目标仓库和端点权限的细粒度 token。
```
go install github.com/26zl/repo-harden/cmd/repo-harden@latest
# 或者从 source 构建:
go build -o repo-harden ./cmd/repo-harden
```
## 对比分析
| | repo-harden | Scorecard / Legitify | Allstar / safe-settings | Terraform GH provider |
| --- | :---: | :---: | :---: | :---: |
| 报告差距 | ✅ | ✅ | ✅ | n/a |
| **应用修复** | **✅** | ❌ | ✅ | ✅ |
| 可还原(单一命令) | **✅** | n/a | 部分 | 通过 state |
| 多平台审计 | **✅** | 部分 | ❌ | ❌ |
| 所需基础设施 | **无** | 无 | App 配置仓库 | IaC + state 后端 |
| 单一二进制文件 | **✅** | 混合 | ❌ | ❌ |
## 背景
repo-harden 最初是一个业余项目 —— 我为自己的仓库构建的一个工具,因为我希望只需一条命令就能对它们进行审计和加固,而无需安装应用程序或搭建基础设施。事实证明它足够实用,因此我将其公开,希望能对其他人有所帮助。
## 生产环境运维
在打 release 标签之前:
1. 确认受保护的 `main` 分支提交已通过 CI 和 CodeQL。
2. 验证 GitHub 中的分支/标签规则集、受限的 Actions 策略、只读
`GITHUB_TOKEN`、secret scanning、push protection 以及私密漏洞
报告。
3. 针对一次性的 GitHub.com、GHES、GitLab、
Gitea 和 Forgejo 项目运行只读审计冒烟测试。在 GitHub.com 上,
还需执行 `harden --dry-run`、应用更改以及 `revert`,
同时检查部分失败后的状态恢复情况。
4. 验证发布包含 Linux、macOS 和 Windows 归档文件、校验和、
每个归档文件的 SBOM 以及构建来源证明。在每一个受支持的操作系统家族上
安装并对一个归档文件进行冒烟测试。
Provider 冒烟测试需要外部实例和凭证,因此
仅凭 Pull Request CI 是无法完成验证的。
## 贡献
```
go test ./...
go vet ./...
```
控制措施位于 `internal/repoharden/controls.go`(基线,可自动修复)和 `internal/repoharden/audit_github.go`(只读审计目录)中;其他平台的审计位于 `internal/repoharden/audit_providers.go`。每个基线控制措施都是一个 `Control{Detect, Apply, Revert}` 结构 —— 添加一项新的检查是一个很好的首次贡献。欢迎提交 Issues 和 PR。
## 许可证
[MIT](LICENSE)
标签:DevSecOps, EVTX分析, GitHub安全, Go, LNA, Ruby工具, 上游代理, 日志审计, 配置加固