fox5t4r/My-CTF-Challenge
GitHub: fox5t4r/My-CTF-Challenge
一个通过 GitHub Issue 表单和 Actions 自动化 Git 子模块添加、验证与更新流程的仓库模板。
Stars: 0 | Forks: 0
# 子模块集合模板
**English** | [한국어](README_KR.md)
[](../../generate)
一个 GitHub 仓库模板,用于将多个 Git 仓库作为子模块进行集中管理。
无需在每次添加子模块时手动编辑 `.gitmodules`、gitlink 和路径,用户可以通过 Issue 表单提交仓库和目标路径。GitHub Actions 会验证该请求并自动创建 pull request。
## 功能
- 通过 Issue 表单接收仓库和父级路径
- 根据仓库名称生成最终的目录名
- 可选择覆盖目录名和跟踪的 branch
- 验证仓库的可访问性和 branch 是否存在
- 检测重复的仓库和重复的路径
- 支持 Unicode、空格、撇号、分号及类似的路径字符
- 在 issue 评论中显示验证错误和最终路径
- 仅在拥有写入权限的维护者评论 `/approve` 后才创建 pull request
- 可从 Actions 页面手动更新所有子模块或选定的单个子模块
- 仅当有更新的 commit 可用时才创建更新 pull request
- 可选使用单独的 token 访问私有 GitHub 仓库
- 使用无依赖的纯 Node.js,无需安装步骤
## 工作流
```
Submit the Issue Form
↓
Validate repository, path, and duplicates
↓
Preview the final path in an issue comment
↓
A maintainer comments /approve
↓
Create a branch and pull request for the submodule
↓
Review and merge
```
手动更新的工作方式如下:
```
Actions → Update submodules → Run workflow
↓
Resolve the tracked branch for all or one submodule
↓
Update gitlinks to the latest remote commits
↓
Create a pull request only when changes exist
↓
Review and merge
```
## 快速开始
### 1. 从模板创建仓库
1. 点击 `Use this template`。
2. 选择 `Create a new repository`。
3. 选择仓库名称和可见性。
4. 创建仓库。
GitHub 会将此模板的文件和目录结构复制到新仓库中。
### 2. 启用 Issues
打开:
```
Settings → General → Features → Issues
```
如果 `Issues` 被禁用,请将其启用。
对于受管理的集合,请在 `Issues` 旁边的下拉菜单中选择 `Collaborators only`。这可以防止外部用户开启请求 issue 并触发预览工作流运行。此限制适用于仓库中的每个新 issue,而不仅仅是子模块请求表单。请参阅 [GitHub 的 issues 设置文档](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/disabling-issues)。
### 3. 授予 GitHub Actions 写入权限
打开:
```
Settings → Actions → General → Workflow permissions
```
启用:
- `Read and write permissions`
- `Allow GitHub Actions to create and approve pull requests`
如果没有这些设置,请求验证仍可运行,但推送 branch 或创建 pull request 可能会失败。
### 4. 请求子模块
打开:
```
Issues → New issue → Add a submodule
```
表单包含以下字段:
| 字段 | 必填 | 描述 |
| --- | --- | --- |
| Repository | 是 | `owner/repository` 或 GitHub HTTPS URL |
| Parent path | 是 | 子模块的父目录。仓库根目录请使用 `.` |
| Directory name | 否 | 留空时使用仓库名称 |
| Branch | 否 | 留空时使用远程仓库的默认 branch |
| Confirmation | 是 | 确认已对仓库和父级路径进行了审查 |
示例:
```
Repository: example/example
Parent path: collections
Directory name: example
Branch: main
Confirmation: checked
```
生成的路径:
```
collections/example
```
创建或编辑 issue 会触发一个工作流,该工作流会将验证结果和最终路径作为评论发布。
### 5. 批准请求
在审查成功的验证结果后,拥有 `write`、`maintain` 或 `admin` 权限的用户可以评论:
```
/approve
```
工作流会验证批准者的仓库权限,并再次验证最新的 issue 内容。然后它会:
1. 创建一个 `submodule/issue-` branch。
2. 运行 `git submodule add`。
3. 提交 `.gitmodules` 和 gitlink。
4. 创建一个 pull request。
5. 在 issue 上发布 pull request 的 URL。
pull request 的正文包含 `Closes #`,因此合并该请求也会关闭对应的请求 issue。
## 手动更新子模块
要将已注册的子模块更新为其最新跟踪的 commit,请打开:
```
Actions → Update submodules → Run workflow
```
可选的 `path` 输入项用于控制更新范围:
| 输入项 | 行为 |
| --- | --- |
| 为空 | 更新在 `.gitmodules` 中注册的每个子模块 |
| 精确路径 | 仅更新选定的子模块 |
示例路径:
```
collections/example
```
该值必须与 `.gitmodules` 中的 `path` 条目完全匹配。如果缺失或拼写错误,工作流将失败并在日志中列出可用路径。
更新工作流使用以下规则选择目标 commit:
1. 当子模块在 `.gitmodules` 中有 `branch` 条目时,更新到该 branch 上的最新 commit。
2. 否则,更新到远程仓库默认 branch 上的最新 commit。
例如,此子模块跟踪 `main`:
```
[submodule "collections/example"]
path = collections/example
url = https://github.com/example/example.git
branch = main
```
当存在更新时,工作流会创建一个 branch 和 pull request,如下所示:
```
submodule/update-
```
pull request 会列出每个已更改子模块的先前 commit 和更新后的 commit。当每个选定的子模块都已是最新状态时,则不会创建任何 branch 或 pull request;结果仅显示在工作流摘要中。
## 支持的仓库输入
默认配置仅接受 GitHub HTTPS 仓库。
这些输入会被归一化为同一个仓库:
```
example/example
https://github.com/example/example
https://github.com/example/example.git
```
归一化结果:
```
https://github.com/example/example.git
```
SSH URL、`file://` URL、内嵌凭据、查询字符串和 fragments 都会被拒绝。
## 限制仓库所有者
使用 `scripts/submodule-manager.mjs` 顶部的 `whitelist_owner` 数组来限制可以添加的仓库所有者。
默认的空数组允许所有所有者:
```
export const whitelist_owner = [];
```
添加所有者名称以仅允许选定的用户或组织:
```
export const whitelist_owner = [
'example',
'example-org',
];
```
当数组中至少包含一个值时,仅接受由列表中所有者拥有的仓库。所有者匹配不区分大小写,这与 GitHub 的行为一致。
```
example/example → allowed
example-org/example → allowed
other-owner/example → rejected
```
对于完整的 HTTPS URL,hostname 之后的第一段路径将被视为所有者。
## 配置
在 `.github/submodule-manager.json` 中自定义行为:
```
{
"allowed_hosts": [
"github.com"
],
"authenticated_hosts": [
"github.com"
],
"allow_root": true,
"portable_paths": true,
"prevent_duplicate_repository": true,
"prevent_case_insensitive_path": true
}
```
### `allowed_hosts`
请求可以使用的 HTTPS Git 主机列表。
```
{
"allowed_hosts": [
"github.com",
"git.example.com"
]
}
```
`owner/repository` 简写总是解析为 `github.com`。若要使用其他主机,请提供完整的 HTTPS URL。
### `authenticated_hosts`
`allowed_hosts` 的子集,可以接收 `SUBMODULE_TOKEN`。默认仅包含 `github.com`;请勿将公开的自定义主机放入此列表。仅当 token 适用于特定的私有自定义主机时,才将其显式添加到此列表中。
```
{
"allowed_hosts": [
"github.com",
"git.example.com"
],
"authenticated_hosts": [
"github.com"
]
}
```
### `allow_root`
当设为 `true` 时,用户可以输入 `.` 作为父级路径,以便在仓库根目录下添加子模块。
### `portable_paths`
当设为 `true` 时,验证器会拒绝可能导致 Windows 上无法 checkout 的保留名称和字符。Unicode、空格、撇号和分号仍然受支持。
### `prevent_duplicate_repository`
当 `.gitmodules` 中已包含相同的仓库 URL 时,拒绝该请求。GitHub URL 会在对大小写进行归一化并处理可选的 `.git` 后缀之后再进行比较。
### `prevent_case_insensitive_path`
拒绝在不区分大小写的文件系统上会发生冲突的路径。
例如,当 `Collections/Example` 已经存在时,`collections/example` 也会被视为重复。
## 私有子模块
默认的 `GITHUB_TOKEN` 仅限于集合仓库使用,可能无法读取其他私有仓库。
要添加私有仓库,请在集合仓库中创建一个 `SUBMODULE_TOKEN` Actions secret。对于不接受 `x-access-token` 作为 HTTPS 用户名的主机,还需使用所需的用户名创建 `SUBMODULE_TOKEN_USERNAME`:
```
Settings → Secrets and variables → Actions → New repository secret
```
建议的权限设置:
- 使用 fine-grained personal access token。
- 仅授予目标私有仓库的 `Contents: Read-only` 权限。
- 请勿授予集合仓库的写入权限。
- 使用尽可能短的有效期。
该 token 仅在获得写入权限的 `/approve` 进行重新验证和添加目标子模块之后,以及在 `authenticated_hosts` 上进行手动更新期间使用。公开的 issue 预览绝不会收到此 token,因此在经过授权的协作者批准之前,私有仓库可能会显示为无法访问。目标 Git 命令在应用此 token 之前,会显式丢弃集合仓库的 checkout 凭据。集合仓库中的 branch 会使用默认的 `GITHUB_TOKEN` 进行推送。
## 验证规则
请求必须满足以下所有条件:
- 使用位于允许主机上的 HTTPS 仓库
- 使用该主机的默认 HTTPS 端口
- 指向可访问的仓库
- 在指定 branch 时,该 branch 必须存在
- 包含从 Issue 表单中勾选的确认信息
- 使用相对路径
- 不包含 `.` 或 `..` 路径段
- 避开 `.git` 内部的路径
- 不包含控制字符或换行符
- 不与 `.gitmodules` 中已注册的等效 HTTPS、SSH 或 scp 风格仓库重复
- 在不区分大小写的文件系统上不与已跟踪的路径发生冲突
- 不会穿越现有父级路径中的符号链接
批准操作会将审查时的 branch 和 commit 绑定到 pull request 中暂存的 gitlink。如果远程仓库在审查后发生移动,工作流将 checkout 所审查的 commit,或者在未推送 pull request 的情况下直接失败。
用户输入永远不会被拼接到 shell 命令中。验证之后,Node.js 脚本会通过 `child_process` 将值作为独立参数传递。
该管理器仅使用 Node.js 标准库。工作流调用 GitHub 托管的 `ubuntu-latest` runner 上已安装的 Node.js 版本,且不会运行 `actions/setup-node`、`npm install` 或 `npm ci`。实际的工作流耗时通常主要来自于 runner 启动和远程 Git 操作。
## 发布此模板
将此项目推送到 GitHub 后,在以下位置启用模板模式:
```
Settings → General → Template repository
```
启用后,GitHub 将在仓库顶部显示 `Use this template` 按钮。
此 README 顶部的徽章使用的是相对链接,因此重命名模板仓库无需更新徽章 URL。
## 项目结构
```
.
├── .github
│ ├── ISSUE_TEMPLATE
│ │ ├── add-submodule.yml
│ │ └── config.yml
│ ├── workflows
│ │ ├── approve-submodule-request.yml
│ │ ├── preview-submodule-request.yml
│ │ └── update-submodules.yml
│ └── submodule-manager.json
├── scripts
│ └── submodule-manager.mjs
├── LICENSE
├── README.md
└── README_KR.md
```
## 注意事项
- 工作流创建的 pull request 永远不会自动合并。
- 编辑请求 issue 会刷新其预览评论。
- 提交 `/approve` 时会再次验证最新的 issue 内容。
- 如果该 issue 的自动化 branch 已经存在 pull request,则不会再创建另一个。没有 pull request 的孤立 branch 会被保留,并且重试会使用新的特定运行 branch。
- 使用默认 `GITHUB_TOKEN` 创建的 pull request 可能无法触发其他工作流。如果在创建 pull request 之后必须运行额外的 CI,请使用 GitHub App 或其他 token。
## 许可证
MIT License
标签:MITM代理, 自定义脚本