内容
<p align="center">
<img src="docs/assets/logo.png" alt="octobroker — 安全 GitHub 网关,用于 AI 代理" width="360">
</p>
一个安全、云原生的 GitHub 网关,用于 AI 编码代理。代理获得 GitHub 的官方 MCP 工具、REST/GraphQL 读取,甚至 `git push` — **无需持有单个 GitHub 凭证**。octobroker 使用可吊销的密钥对每个代理进行身份验证,强制执行每个代理的默认拒绝工具和仓库策略,并按需为多个组织创建短期的、仓库范围的 GitHub 应用令牌。
> [octobroker.dev](https://octobroker.dev) · 设计:[docs/DESIGN.md](docs/DESIGN.md) · 入门指南:[docs/getting-started.md](docs/getting-started.md) · RFC 历史:[#15](https://github.com/openabdev/octobroker/issues/15)
## 设计原则
- **代理上没有 GitHub 凭证** — 代理最多持有 octobroker API 密钥(可吊销、策略绑定、不是 GitHub 凭证)。GitHub 凭证存在于一个地方:octobroker。
- **默认拒绝策略引擎** — 每个代理都有一个确切的工具允许列表和仓库允许列表;新的上游工具在明确授予之前被拒绝。GitHub 自己的作用域安装令牌独立于 octobroker 的解析强制执行仓库边界。
- **首选短期凭证** — GitHub 应用安装令牌(1 小时,自动刷新,仓库范围)是推荐的后端。长期 PAT 池仍然用于 REST 读取缓存和旧设置。
- **云原生** — 在任何 Kubernetes(Amazon EKS、Google Cloud GKE、自托管 k8s)和 Amazon ECS 上运行。单个静态二进制文件,无运行时依赖。
- **密钥优先** — 凭证在运行时从 AWS Secrets Manager 或 Kubernetes 机密中解析。没有纯文本令牌。
- **私有网络隔离** — 设计为在您的受信任网络(VPC、服务网格)中运行。没有公共端点;仅出口到 GitHub。
## 架构
```
┌─────────────────────────────────────────────────────────────────────┐
│ 私有网络 / VPC │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 代理 A │ │ 代理 B │ │ gh CLI │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ octobroker │ │
│ │ │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ 代理身份验证(X-Octobroker-Key)│ │ │
│ │ │ + 默认拒绝策略 │ │ ┌────────────────┐ │
│ │ │ 工具/仓库每个代理 │ │ │ 机密管理器 │ │
│ │ └────────────────────────────┘ │ │ (AWS/K8s/环境)│ │
│ │ ┌─────────────┐ ┌────────────┐ │ └───────┬────────┘ │
│ │ │ GitHub 应用 │ │ PAT 池 │◄─┼──────────┘ │
│ │ │ 令牌(1 小时,│ │ (REST 读取│ │ │
│ │ │ 仓库范围)│ │ 预算) │ │ │
│ │ └─────────────┘ └────────────┘ │ │
│ │ ┌─────────────┐ ┌────────────┐ │ │
│ │ │ 失败关闭 │ │ 缓存 │ │ │
│ │ │ 写审计 │ │ (内存)│ │ │
│ │ └─────────────┘ └────────────┘ │ │
│ └───────┬──────────────────┬───────┘ │
│ │ │ │
└───────────────────┼──────────────────┼──────────────────────────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌───────────────────┐
│ api.githubcopilot │ │ api.github.com │
│ .com/mcp/ (MCP) │ │ (REST/GraphQL) │
└─────────────────────┘ └───────────────────┘
请求流程:
GET /repos/org/repo/pulls
→ 缓存命中?返回缓存
→ 缓存未命中:选择具有最高剩余预算的 PAT
→ 转发到 GitHub,缓存响应,更新速率限制
POST /graphql(查询)
→ 缓存命中?返回缓存
→ 缓存未命中:选择池化的 PAT,转发,缓存响应
POST /graphql(突变)
→ 需要客户端授权头
→ 直通到 GitHub(无池化,无缓存)
→ 从令牌中解析 + 记录 GitHub 用户名
POST /mcp(可选;默认为只读,写入在严格控制后)
→ MCP 流式 HTTP 反向代理到 GitHub 的托管 MCP 服务器
→ 代理身份验证(X-Octobroker-Key)→ 默认拒绝工具/仓库策略
→ 注入范围的 GitHub 应用令牌(或池化的 PAT),按会话固定
→ 每个工具/调用审计日志;写入失败关闭审计
## 它做什么
- 池化多个 GitHub PAT,并通过具有最多剩余速率限制预算的身份路由每个读取请求
- 使用可配置的 TTL 在内存中缓存 GitHub REST 和 GraphQL 查询响应
- 代理 GraphQL 突变,使用直通身份验证(客户端自己的令牌,无缓存)
- **MCP 反向代理**(可选) — 代理连接到 `/mcp` 并获得 GitHub 的官方 MCP 工具 **而无需代理上的 GitHub 凭证**;每个代理密钥 + 默认拒绝工具/仓库允许列表,GitHub 应用凭证和严格控制的审计写入
- **Git 凭证代理**(可选) — `obk` 作为 git 凭证助手:在 `git push` 时,它用短期、单个仓库、仅限内容的 GitHub 应用令牌交换代理的 octobroker 密钥 — 代理容器中没有存储的 git 凭证
- 镜像 GitHub API 路径结构 — 客户端只需更改基准 URL
- 仅限于配置的组织/所有者仓库
- 自动从令牌中解析 GitHub 用户名用于审计日志
## 快速入门
> **新来者?遵循 [入门指南](docs/getting-started.md)** — 从五分钟的本地运行到每个代理的身份验证、GitHub 应用后端和审计写入。
```sh
cp config.example.toml config.toml
# 使用您的 PAT 和允许的所有者编辑 config.toml
cargo run --release
# 监听 0.0.0.0:8080
curl http://localhost:8080/repos/openclaw/chi/pulls/123
curl http://localhost:8080/stats
```
## 配置
### TOML 文件
配置文件搜索顺序:
1. `OCTOBROKER_CONFIG` 环境变量(显式路径 — 始终获胜)
2. `./config.toml`(当前目录)
3. `$XDG_CONFIG_HOME/octobroker/config.toml`(默认为 `~/.config/octobroker/config.toml`)
4. 没有文件 → 仅环境变量(见下文)
加载的路径在启动时记录。对于家目录中的配置文件,请首选机密引用(`env:`, `aws:secretsmanager:`, `k8s:`)而不是纯文本令牌字面值。
参见 [config.example.toml](config.example.toml) 获取所有选项。
### 机密引用
`[[identities]]` 中的 `token` 字段支持多个机密源,因此凭证永远不需要在磁盘上以纯文本形式存在:
| 格式 | 源 |
|--------|--------|
| `ghp_xxx...` | 纯文本字面值(仅本地开发) |
| `env:VAR_NAME` | 环境变量 |
| `aws:secretsmanager:secret-name:json-key` | AWS 机密管理器 |
| `k8s:namespace/secret-name:key` | Kubernetes 机密(挂载卷) |
#### AWS 机密管理器
将 PAT 存储为单个机密中的 JSON 对象:
```sh
aws secretsmanager create-secret --name octobroker/pats \
--secret-string '{"pat_alice":"ghp_xxx","pat_bob":"ghp_yyy"}'
```
```toml
[[identities]]
id = "alice"
token = "aws:secretsmanager:octobroker/pats:pat_alice"
```
octobroker 使用标准 AWS 凭证链(实例配置文件、ECS 任务角色、SSO、环境变量)。
#### Google Cloud 机密管理器(计划中)
```toml
[[identities]]
id = "alice"
token = "gcp:secretmanager:projects/my-proj/secrets/octobroker-pat:latest"
```
GCP 支持正在规划中。欢迎贡献。
#### Kubernetes 机密
将您的机密作为卷挂载到 `/etc/secrets/` 并引用它:
```yaml
# Kubernetes 机密
apiVersion: v1
kind: Secret
metadata:
name: octobroker-pats
namespace: default
stringData:
pat_alice: ghp_xxx
```
```toml
[[identities]]
id = "alice"
token = "k8s:default/octobroker-pats:pat_alice"
```
适用于任何 Kubernetes 发行版 — EKS、GKE、AKS、k3s 或自托管。
### 仅环境变量
```sh
export OCTOBROKER_PORT=8080
export OCTOBROKER_ALLOWED_OWNERS=openclaw,openabdev
export OCTOBROKER_PAT_ALICE=ghp_xxx
export OCTOBROKER_PAT_BOB=ghp_yyy
```
PAT 从任何与 `OCTOBROKER_PAT_<ID>=<token>` 匹配的环境变量中发现。
## 部署
### Docker
```sh
docker build -t octobroker .
docker run -p 8080:8080 -v ./config.toml:/config.toml octobroker
```
### ECS(服务连接)
作为 ECS 集群中的服务部署。使用 Cloud Map 命名空间,其他服务通过以下方式访问它:
```
http://octobroker.<namespace>:8080/repos/owner/repo/pulls/123
```
### Kubernetes
作为 ClusterIP 服务部署。其他 Pod 通过以下方式访问它:
```
http://octobroker.<namespace>.svc.cluster.local:8080/repos/owner/repo/pulls/123
```
## API
### REST(GET)
所有 GitHub REST API GET 路径都被透明地代理,并使用 PAT 池和缓存:
```
GET /<github-api-path>
```
### GraphQL(POST /graphql)
```
POST /graphql
```
- **查询** — 通过池化的 PAT 路由,缓存响应
- **突变** — 客户端自己的 `Authorization` 头传递给 GitHub(无池化,无缓存)
如果突变请求没有 `Authorization` 头,octobroker 返回 `401`。
```
┌────────────────────────────────────────────────────────────────┐
│ POST /graphql │
│ │
│ 解析请求体 → 提取 "query" 字段 │
│ │
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
│ │ 以 "query" 开头 │ │ 以 "mutation" 开头 │ │
│ └──────────┬──────────┘ └──────────────┬─────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
│ │ 检查缓存 │ │ 需要客户端 │ │
│ │ HIT → 返回 │ │ 授权头 │ │
│ │ MISS ↓ │ │ 丢失 → 401 │ │
│ └──────────┬──────────┘ └──────────────┬─────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
│ │ 选择池化的 PAT │ │ 直通客户端的令牌 │ │
│ │ (最高预算) │ │ (身份保留) │ │
│ └──────────┬──────────┘ └──────────────┬─────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
│ │ 转发到 GitHub │ │ 转发到 GitHub │ │
│ │ 缓存响应 │ │ 无缓存 │ │
│ │ 更新速率限制 │ │ 记录解析的用户名 │ │
│ └─────────────────────┘ └────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
```
### MCP(POST/GET/DELETE /mcp)— 可选
反向代理到 [GitHub 的托管 MCP 服务器](https://github.com/github/github-mcp-server):代理连接到 octobroker 并获得 GitHub 的官方 MCP 工具 **而无需代理上的 GitHub 凭证**。octobroker 剥离任何客户端 `Authorization` 头并注入上游的池化凭证。
> **状态:写入在严格控制后可用。** 默认情况下为只读;`enable_writes` 解锁写入工具仅适用于经过身份验证的代理,并且需要 GitHub 应用后端加上关闭的审计(在启动时验证)。参见 [RFC](https://github.com/openabdev/octobroker/issues/15).
```
┌───────────────── 私有网络 / VPC ─────────────────┐
│ │
│ ┌───────────────────┐ ┌────────────────────┐ │
│ │ MCP 客户端 │ │ octobroker │ │
│ │ (代理) │ MCP │ │ │
│ │ │ ──────► │ 1. 剥离客户端 │ │
│ │ 无 GitHub │ HTTP │ 授权 │ │
│ │ 凭证 │ ◄────── │ 2. 固定池化的 │ │
│ └───────────────────┘ │ 令牌/会话 │ │
│ │ 3. 审计日志 │ │
│ │ 工具/调用 │ │
│ └─────────┬──────────┘ │
└──────────────────────────────────────────┼──────────────┘
│ Bearer <池化凭证>
▼
┌──────────────────────────────┐
│ api.githubcopilot.com/mcp/ │
│ 只读 (托管,GitHub- │
│ 维护的工具模式) │
└──────────────────────────────┘
```
在 `config.toml` 中启用它(或 `OCTOBROKER_MCP_ENABLED=true`):
```toml
[mcp]
enabled = true
# upstream = "https://api.githubcopilot.com/mcp/readonly" # 默认
# toolsets = ["issues", "pull_requests", "repos"] # 可选粗糙过滤
# session_ttl_secs = 3600 # 会话固定空闲 TTL
```
行为说明:
- **会话固定** — 池化身份在 `initialize` 时选择,并在整个 MCP 会话中重用。未知或过期的会话会得到 `404`(按 MCP 规范)并且客户端会透明地重新初始化。
- **工具名称与写入服务器不同** — 只读界面使用例如 `issue_read`,不使用 `get_issue`。通过 `tools/list` 发现它们。
- **审计日志** — 每个 JSON-RPC 帧都记录方法、工具名称、身份和会话:`MCP 工具/调用 issue_read [via alice] [session=7b86a7eb]`。
- **`allowed_owners` 在 `/mcp` 上不强制执行** — 没有配置 `[[mcp.agents]]`,访问仅限于池化凭证的权限和只读上游仓库级别控制。配置每个代理的 `repos` 允许列表(如下)。
#### 每个代理的身份验证(第 2a 阶段)
添加 `[[mcp.agents]]` 条目,要求在每个 `/mcp` 请求上使用 API 密钥,并强制执行 **默认拒绝工具允许列表** 每个代理:
```toml
[[mcp.agents]]
id = "openab-bot"
key = "aws:secretsmanager:octobroker/mcp-keys:openab" # env:/k8s: 引用也有效
tools = ["issue_read", "list_issues", "pull_request_read"]
```
- 配置任何代理后,请求没有有效的 `X-Octobroker-Key` 会得到 `401`;`tools/call` 对于不在代理的允许列表中的工具会得到 `403` 在代理 - 它永远不会到达 GitHub。允许列表也会作为 `X-MCP-Tools` 注入上游,因此 `tools/list` 原生显示代理仅其允许的工具。
- 新的上游工具 **默认拒绝** 直到添加到代理的 `tools` 列表中。
- 密钥是 **octobroker 凭证,不是 GitHub 凭证** - 泄漏仅限于该代理的允许列表,并在编辑 octobroker 配置时被撤销,而无需触摸 GitHub。
- 审计行包括代理:`MCP 工具/调用 issue_read [agent=openab-bot via alice] [session=…]`.
- 在生产中终止 TLS 前面 octobroker(ALB,ingress,网格)- 密钥在标头中传输。
客户端配置增加一行:```json
{
"mcpServers": {
"github": {
"url": "http://octobroker.<namespace>:8080/mcp",
"headers": { "X-Octobroker-Key": "${OCTOBROKER_KEY}" }
}
}
```
**第 2b 阶段:写入访问**
```toml
[mcp]
enabled = true
enable_writes = true # 启动失败,除非所有三个部分都存在
```
# 最大并发写入数 = 4 # 每个代理的写入并发上限(0 = 无限制)
[mcp.github_app] # 写入操作从不运行在共享的PAT上
app_id = "123456"
private_key = "aws:secretsmanager:octobroker/app:private_key"
owner = "openabdev"
[mcp.audit] # 写入操作会被关闭并审计
path = "/var/lib/octobroker/mcp-audit.jsonl"
[[mcp.agents]] # 写入操作仅适用于已认证的代理
id = "openab-bot"
key = "aws:secretsmanager:octobroker/mcp-keys:openab"
tools = ["issue_read", "create_issue", "add_issue_comment", "octobroker_review_minimize_comment"]
repos = ["openabdev/octobroker", "openabdev/openab"]
## 写入路径的限制
- **默认拒绝栈**: 代理密钥 → 工具允许列表 → 写入分类 → 仓库允许列表(拒绝如果无法解析)→ 每个代理的并发上限 → 关闭失败审计记录 → 转发。
- **作用域凭证**: 当一个代理的 `repos` 都是一个所有者的精确条目时,其安装令牌会使用 API 的 `repositories` 参数进行铸造 - **GitHub本身强制执行仓库边界**,独立于 octobroker 的参数解析。通配符或混合所有者允许列表会回落到安装范围内的令牌(代理侧检查仍然适用)。
- **审计**: 每次写入操作有两个 fsync'd JSONL 记录(飞行前 + 结果)。结果捕获 MCP 工具结果(`result.isError`)- 单独的 HTTP 200 不被视为成功。如果飞行前记录无法持久化,写入操作将被拒绝(503)而无需到达 GitHub。参数值永远不会被记录。
- **无自动重试**: octobroker 永远不会重试转发调用;不明确的写入结果(例如响应过程中连接丢失)被记录为无法确定,并被暴露给客户端 - 重试决策属于调用者。
- **吊销**: 会话 pin 位于进程内存中;密钥轮换使用双 `keys`,并且任何配置更改(禁用代理,策略收紧)通过重启生效,这会清除所有会话。上游会话 DELETE 在 GitHub 上是一个 no-op - octobroker 的 pin 缓存是会话权限。
## 所需的 GitHub 应用权限(仅授予您的代理工具所需的权限)
| 工具 | 应用权限 |
|-------|----------------|
| `issue_read`, `list_issues`, `create_issue`, `add_issue_comment` | 问题: 读取 / 写入 |
| `octobroker_review_minimize_comment` | 问题: 写入 和 拉取请求: 写入 |
| `pull_request_read`, `create_pull_request`, `merge_pull_request` | 拉取请求: 读取 / 写入 |
| `get_file_contents`, `create_or_update_file`, `push_files` | 内容: 读取 / 写入 |
| `list_workflows`, `run_workflow` | 操作: 读取 / 写入 |
## octobroker 所属的评论工具(问题 #44 MVP)
当启用写入操作并且经过身份验证的代理在允许列表中显式包含该工具时,`tools/list` 也会宣传它。例如:
```toml
[[mcp.agents]]
id = "review-bot"
key = "env:OCTOBROKER_REVIEW_KEY"
tools = ["issue_read", "list_issues", "octobroker_review_minimize_comment"]
repos = ["openabdev/octobroker"]
```
该工具接受 `owner`、`repo`、`node_id` 和一个 `classifier`(`ABUSE`、`DUPLICATE`、`OFF_TOPIC`、`OUTDATED`、`RESOLVED` 或 `SPAM`)。它支持由当前 GitHub 应用机器人身份撰写的 问题 和 拉取请求 评论;它不会减少人类撰写的评论或不支持的节点类型。在进行变更之前,它会验证应用程序机器人的作者和确切的仓库所有者/名称是否与策略参数一致,然后通过 octobroker 的作用域 GitHub 应用凭证在本地执行 GitHub 的 `minimizeComment` GraphQL 变更。该操作不会被转发到上游 MCP 服务器。调用使用与上游写入工具相同的仓库策略、写入门、并发限制和关闭失败审计。未显式允许该名称的代理,或写入操作被禁用的代理,既看不到 `tools/list`,也无法调用它。
这是故意为 MVP 设计的狭窄范围:octobroker 不公开任意 GraphQL,上游 GitHub MCP 工具保持不变。任何未来的 octobroker 所属工具必须保留相同的显式允许列表、仓库绑定、写入门和审计要求。
`tools/list` 返回的工具表面根据应用的实际权限缩小(在 [#22 spike](https://github.com/openabdev/octobroker/issues/22) 中验证)- 请谨慎授予权限并根据代理的需求进行扩展。
## 多安装路由(一个密钥,许多组织)
一个代理,一个 `X-Octobroker-Key`,一个 MCP 服务器条目 - 几个组织中的仓库。替换单个 `[mcp.github_app]` 为每个安装的 `[[mcp.github_apps]]` 条目(每个组织中的相同应用安装,或每个组织一个应用):
```toml
[[mcp.github_apps]]
app_id = "123456"
private_key = "aws:secretsmanager:octobroker/app:private_key"
owner = "openabdev" # 路由密钥 - 每个条目唯一
installation_id = 11111111 # 推荐: 跳过发现
[[mcp.github_apps]]
app_id = "123456"
private_key = "aws:secretsmanager:octobroker/app:private_key"
owner = "oablab"
installation_id = 22222222
[[mcp.agents]]
id = "b0"
key = "aws:secretsmanager:octobroker/mcp-keys:b0"
tools = ["issue_read", "list_issues", "create_issue", "add_issue_comment"]
repos = ["openabdev/openab", "oablab/chi"] # 所有者选择安装
```
工作原理:
```
b0 初始化(一下游会话)
├─ 上游会话 A ← 仓库作用域令牌,openabdev 安装
└─ 上游会话 B ← 仓库作用域令牌,oablab 安装
tools/call {owner: "openabdev", …} → 会话 A (openabdev 令牌)
tools/call {owner: "oablab", …} → 会话 B (oablab 令牌)
```
- **路由基于参数** - 安装由调用的 `owner`/`repo` 参数解析决定,从不由代理直接选择。`repos` 允许列表之外的所有者被拒绝在任何凭证被触及之前。
- **在 `initialize` 处急切分发** - 代理允许列表中的每个所有者都会生成一个仓库作用域令牌和一个上游会话,如果失败则关闭:任何安装无法生成或初始化,则整个 `initialize` 失败,并且已经打开的上游会话会被清理(尽力而为的 DELETE)。令牌在上游会话中永远不会混合,以保持每个安装的固定不变。
- **一个下游会话** - 客户端看到一个会话 ID;octobroker 将其映射到每个安装的上游会话。`DELETE` 和 `notifications/*` 会分发到每个路由(第二aries 的尽力而为)。当固定的令牌过期时,会话会得到 404,客户端会重新初始化(全新的令牌)。
- **主要路由** - 代理 `repos` 允许列表中按字母顺序排在首位的拥有者。其上游会话 ID 同时作为下游会话 ID,并提供非仓库流量(`tools/list`,GET 流)。
- **仅主要服务器发起的流量** - GET 流恢复和任何客户端→服务器 JSON-RPC 响应通过主要路由的上游会话骑行。GitHub 的托管 MCP 服务器直接在 POST 响应中回答 `tools/call`,因此工具调用不受影响;不支持辅助路由上的服务器发起的交互。
- **授予每个安装相同的应用权限** - `tools/list` 由主要安装提供,因此权限不匹配会导致错误。
- **启动验证** - 复制的所有者、没有 `repos` 的代理以及没有匹配安装的仓库所有者都是配置错误。
- **审计归属** - 写入记录带有确切的安装:`"cred": "github-app:openabdev"`。
- 多安装模式需要 `[[mcp.agents]]` - 没有网络信任变体。
与每个组织一个密钥的权衡:泄漏的密钥可以访问所有已配置安装的允许列表仓库。 **所有** 配置的安装。
## 通过应用令牌的 HTTPS Git(`/git-credential`)
MCP 涵盖问题和拉取请求,但 `git push` 使用 Git 协议 - 它需要推送时的真实凭证。`enable_git_credentials` 允许仓库作用域的代理用 octobroker 密钥交换一个 **短期,单仓库** 应用安装令牌,消除代理容器中剩余的长期 GitHub 凭证:
```toml
[mcp]
enable_git_credentials = true # 与写入相同硬门控:
# 代理 + 应用后端 + [mcp.audit]
```
应用需要目标仓库的 **内容:读取和写入**。使用单个 `[mcp.github_app]` 表单时,所有者 **必填** 当启用 git 凭证时 - 显式 `installation_id` 在颁发令牌之前会与安装的实际帐户进行验证。
代理端,`obk` 兼作标准 git 凭证助手。将它注册为 `github.com` 的 **唯一** 助手 - `--replace-all` 和空的第一条目会清除任何继承的助手(osxkeychain,GCM,`gh auth git-credential` 可能会提供更广泛的凭证):
```sh
git config --global --replace-all credential."https://github.com".helper ""
git config --global --add credential."https://github.com".helper "!obk git-credential"
git config --global credential."https://github.com".useHttpPath true
```
每个 `git push` 操作都会执行以下操作:
```
git push → obk git-credential (环境中的 OCTOBROKER_KEY)
→ GET /git-credential?repo=owner/name (X-Octobroker-Key)
→ 密钥身份验证 → 仓库允许列表 → 安装路由
→ 持久审计预飞行(阶段:git_credential_request)
→ 安装所有者验证为 GitHub
→ 仅限内容的单仓库令牌(〜1小时,GitHub 强制范围)
→ 审计结果(阶段:git_credential_result)
→ 推送认证为 <app>[bot]
```
属性:
- **单仓库,仅限内容令牌** - 每个凭证都使用确切的仓库和 `contents: write` 权限生成,从不使用应用的完整权限集;GitHub 本身强制执行两个边界。Git 令牌与 MCP 令牌分开缓存。
- **所有者绑定** - 配置的所有者标签在颁发和每小时重新验证令牌时,会与安装的实际帐户 (`GET /app/installations/{id}`) 进行验证;错误标记的安装 ID 被拒绝。
- **关闭失败审计** - 请求记录在颁发令牌之前 **和** 令牌返回之前会持久保存;如果写入失败,则无凭证(503)。令牌值永远不会写入审计日志。
- **默认拒绝** - 无仓库的代理、允许列表之外的仓库和没有安装的所有者都会被拒绝在颁发之前。
- **关闭失败助手** - 一旦请求被识别为 `github.com` HTTPS,任何失败(缺少 `OCTOBROKER_KEY`、缺少路径、策略拒绝、网络错误)都会使 `obk` 发出 `quit=true`,告诉 git 停止助手级联而不是回落到更广泛的存储凭证或提示。 不支持 gist.github.com。
- **无需存储** - `store`/`erase` 是无操作;令牌会在其自身过期。响应中的 `cache-control: no-store`。
部署说明:
- 需要额外依赖 `api.githubcopilot.com`(唯一的外部依赖项)。
- 在启用 MCP 时运行 **单个副本** - 会话 pin 位于进程内存中。滚动部署终止会话;客户端通过重新初始化恢复。
- 在受信任的网络中,任何可以访问 `/mcp` 的工作负载都具有相同的只读访问权限(与 octobroker 的 REST 读取相同的信任模型)。在任何具有写入权限的阶段之前,请在前面添加 TLS 和代理身份验证。
- 如果托管的端点在您的网络中无法访问,请将 `upstream` 指向自托管的 [`github-mcp-server`](https://github.com/github/github-mcp-server) - 相同的协议和标头。
### 管理
| 路径 | 描述 |
|------|-------------|
| `GET /healthz` | 健康检查 |
| `GET /stats` | 池和缓存统计 |
## 客户端如何使用它
### obk CLI(推荐)
`obk` 是一个替代 `gh` 的命令行工具,通过 octobroker 的 REST API(连接池 + 缓存)路由读取命令,并直接与 `gh` 写入。
```sh
export OCTOBROKER_URL=http://octobroker.openab.local:8080
# 读取 - 通过 octobroker(连接池 + 缓存)
obk api repos/org/repo --jq .stargazers_count
obk issue list -R org/repo -L 10
obk pr list -R org/repo
obk pr view 123 -R org/repo
obk run list -R org/repo
# 写入 - 回落到真正的 gh(直接访问 GitHub)
obk issue create -R org/repo -t "title" -b "body"
obk issue comment 123 -R org/repo -b "comment"
obk pr create -R org/repo -t "title" -b "body"
```
要透明地替换 `gh`:
```sh
ln -sf $(which obk) ~/bin/gh
export PATH=~/bin:$PATH
```
### gh CLI
```sh
export GITHUB_API_URL=http://localhost:8080
```
REST 调用(`gh api repos/...`)通过 octobroker 路由。注意:`gh` CLI 的内置命令(`gh issue list`、`gh pr list`)内部使用 GraphQL,并绕过 `GITHUB_API_URL` - 使用 `obk` 以获得完整的覆盖。
### 编码代理
将 GitHub API 基地址设置为指向 octobroker:
```sh
export GITHUB_API_BASE=http://localhost:8080
```
### MCP 客户端(代理)
将任何 Streamable-HTTP MCP 客户端指向 octobroker - 无 GitHub 令牌,无 `gh` CLI,无代理容器中的 git 凭证。
Kiro CLI (`~/.kiro/settings/mcp.json`) 和大多数 JSON 配置的客户端:
```json
{
"mcpServers": {
"github": {
"url": "http://octobroker.<namespace>:8080/mcp",
"headers": { "X-Octobroker-Key": "${OCTOBROKER_KEY}" }
}
}
}
```
使用 `[[mcp.agents]]` 配置(推荐),每个请求都需要代理的 `X-Octobroker-Key` - 通过 ECS 任务秘密 / K8s 秘密传递。如果没有配置任何代理(网络信任模式),可以省略 `headers` 行。
Claude 代码:
```sh
claude mcp add --transport http github http://octobroker.<namespace>:8080/mcp \
--header "X-Octobroker-Key: ${OCTOBROKER_KEY}"
```
从容器验证(无 GitHub 凭证):
```sh
curl -s -X POST http://octobroker:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "X-Octobroker-Key: $OCTOBROKER_KEY" \
-d '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}' -i | grep -i mcp-session-id
```
### 直接 curl
```sh
# REST
curl http://localhost:8080/repos/org/repo/pulls/123
# GraphQL 查询
curl -X POST http://localhost:8080/graphql \
-H "Content-Type: application/json" \
-d '{"query":"query { repository(owner:\"org\", name:\"repo\") { stargazerCount }}"}'
# GraphQL 变更(需要您自己的身份验证)
curl -X POST http://localhost:8080/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ghp_your_token" \
-d '{"query":"mutation { addStar(input:{starrableId:\"...\"}) { clientMutationId }}"}'
```
## 许可证
MIT
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器