GitProxy 2.3 常用 CLI 命令与 REST API 详解
面向 GitProxy 2.3 管理员与自动化场景的命令行与接口手册:服务端 gitproxy 启动参数、管理台 REST API(认证/用户/仓库/推送审批)与推送人 CLI 的实测用法,并给出 git push 触发审批的完整闭环回显。
GitProxy 2.3 常用 CLI 命令与 REST API 详解
目标:讲清 GitProxy v2.3.0 的三套操作面——服务端命令行(启动与配置校验)、管理台 REST API(认证 / 用户 / 仓库 / 推送审批四域)、推送人 CLI(
@finos/git-proxy-cli),每条命令都给出真实执行回显,并用git push把「推送 → 审批 → 落地 / 驳回 / 取消」全状态闭环实测一遍。已在 Ubuntu 22.04(x86_64)+ GitProxy v2.3.0 实测通过。
一、环境信息
| 项 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04 LTS(x86_64),GitProxy 部署机兼工作机 |
| GitProxy | v2.3.0(node dist/index.js --version 实测 2.3.0,运行时 Node.js v24.14.0) |
| 部署形态 | Docker Compose + Gitea 1.23.8 上游,见《GitProxy 2.3 Docker Compose 部署指南》 |
| 端口 | Git 代理 8149(HTTP)/ 8151(HTTPS);管理台 8150(HTTP)/ 8152(HTTPS);Gitea 8147 |
| 域名 | gitproxy.local、gitea.local(部署篇 4.4 节已写入服务器 /etc/hosts) |
| 演示账号 | admin(管理员)、reviewer(审批人)、dev1(本篇新建的普通账号),口令均为 q1w2e3r4 |
| Gitea Token | 属主 admin,作用域 read:user + write:repository(交互式录入,不落盘) |
| 配置文件 | /opt/gitproxy-2.3/config/proxy.config.json,csrfProtection: true、rateLimit 60 秒 1000 次,逐键语义见《GitProxy 2.3 配置参数详解》 |
本篇 API 命令统一以 http://gitproxy.local:8150 为基地址(与部署篇的 /etc/hosts 记录一致,等价于 127.0.0.1:8150)。
二、工具概览
GitProxy v2.3.0 提供三个操作面,底层共享同一套数据与权限模型:
| 操作面 | 入口 | 使用者 | 典型用途 |
|---|---|---|---|
| 服务端命令行 | node dist/index.js [options](GitProxy 安装目录内) | 运维 | 启动服务、指定配置文件、改配置前校验合法性 |
| REST API | 管理台 8150 端口,/api/auth(认证)与 /api/v1(业务)两组前缀 | 管理台 UI、脚本/自动化 | 账号与仓库管理、审批、状态查询 |
| 推送人 CLI | git-proxy-cli(@finos/git-proxy-cli 包,v2.3.0) | 推送人 | 登录、查询待审批推送、命令行内审批 |
三者关系:管理台 UI 与本篇所有 curl 命令调用的是同一批 REST 端点;推送人 CLI 是这些端点的薄封装(不实现 CSRF 获取,详见 7.4 节);服务端命令行只负责进程生命周期,与 API 无关。
三、前置条件
- 已按《GitProxy 2.3 Docker Compose 部署指南》完成部署:健康检查正常(
GET /api/v1/healthcheck返回{"message":"ok"}),admin/reviewer账号与仓库授权矩阵就绪(部署篇 4.7 节); /etc/hosts已含gitproxy.local与gitea.local两条记录;- 本机装有
curl与 git 2.34.1(git --version实测),用于 API 调用与推送闭环; - Gitea 侧已为
admin签发 Personal Access Token(作用域read:user+write:repository;网页操作:Settings → Applications → Generate New Token)。推送命令用交互式录入避免明文:
read -s -p "Gitea Token: " GITEA_TOKEN && echo
四、服务端命令行详解
服务端入口是 GitProxy 安装目录下的 node dist/index.js(部署篇 compose 的启动命令即 node --enable-source-maps dist/index.js --config /app/proxy.config.json;--enable-source-maps 是 Node.js 参数,不是 gitproxy 参数)。以下命令均在安装目录内执行。
4.1 命令总览(--help)
node dist/index.js --help
Configuration sources are disabled
Configuration loaded successfully
Usage: index.js [options]
Options:
--help Show help [boolean]
--version Show version number [boolean]
-v, --validate Check the proxy.config.json file in the current working
directory for validation errors. [boolean]
-c, --config Path to custom git-proxy configuration file.
[string] [default: "/app/dist/proxy.config.json"]
三点解读:
- 前两行是启动日志而非帮助文本的一部分:每次执行(包括
--help)都会先加载配置,Configuration sources are disabled表示外部配置源特性未启用(配置参数详解篇 5.14 节); -c的默认值是安装目录内的dist/proxy.config.json(发布包内置默认配置),不带--config启动时读的就是它——这正是部署篇 4.4 节强制command里显式传--config /app/proxy.config.json的原因;- 没有独立的
start子命令:不带--help/--version/-v执行即直接启动服务。
4.2 --version
node dist/index.js --version
Configuration loaded successfully
2.3.0
4.3 配置校验(-v / --validate)
校验模式只做检查、不启动服务。不带 -c 时按默认路径检查:
node dist/index.js -v
Configuration sources are disabled
Configuration loaded successfully
Setting config file to: /app/dist/proxy.config.json
/app/dist/proxy.config.json is valid
校验部署实际加载的配置文件(部署篇挂载进来的 /app/proxy.config.json):
node dist/index.js -v -c /app/proxy.config.json
Configuration sources are disabled
Configuration loaded successfully
Setting config file to: /app/proxy.config.json
/app/proxy.config.json is valid
把合法配置改成非法(比如 serverPort 传字符串)后再校验,会得到明确的键名与类型报错,这一形态的完整实测见配置参数详解篇 3.3 节。运维惯例:改配置 → -v -c 校验 → 重启服务。
五、REST API 详解
5.1 认证与会话(/api/auth)
csrfProtection: true 时,所有写请求(POST/PUT/PATCH/DELETE)都必须先取 CSRF Token 并随 X-CSRF-Token 头提交,同时用 Cookie 维持会话。Token 每次写操作前都要重新获取——复用旧 Token 会得到 401(实测回显):
{"message":"CSRF token mismatch"}
统一约定:会话 Cookie 存入 admin.jar,用 python3 -c 从响应里提取 Token 到变量。完整登录闭环:
CT=$(curl -s -c admin.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -b admin.jar -c admin.jar -X POST http://gitproxy.local:8150/api/auth/login \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" \
-d '{"username":"admin","password":"q1w2e3r4"}'
{"message":"success","user":{"username":"admin","displayName":"","email":"admin@place.com","title":"","scmIdentities":{"local-gitea":"admin"},"admin":true}}
scmIdentities 显示该账号已绑定 SCM 供应商身份 local-gitea(推送时网关据此映射凭据,见配置参数详解篇 5.12 节)。当前会话信息与会话终止:
curl -s -b admin.jar http://gitproxy.local:8150/api/auth/profile
{"username":"admin","displayName":"","email":"admin@place.com","title":"","scmIdentities":{"local-gitea":"admin"},"admin":true}
CT=$(curl -s -b admin.jar -c admin.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -b admin.jar -c admin.jar -X POST http://gitproxy.local:8150/api/auth/logout -H "X-CSRF-Token: $CT"
{"isAuth":false,"user":null}
登出后再查 profile 返回 401:
{"message":"Not logged in"}
健康检查无需会话:
curl -s http://gitproxy.local:8150/api/v1/healthcheck
{"message":"ok"}
5.2 用户域(/api/v1/user + 创建/改密)
用户清单(管理员会话)。返回数组,每项含 _id、username、email、admin、scmIdentities 等字段;本环境当前 5 个账号:
curl -s -b admin.jar http://gitproxy.local:8150/api/v1/user | python3 -c "import json,sys;[print(u['username'],'| admin:',u['admin'],'|',u['email']) for u in json.load(sys.stdin)]"
admin | admin: True | admin@place.com
user | admin: False | user@place.com
reviewer | admin: False | reviewer@example.com
dev1 | admin: False | dev1@example.com
democli | admin: False | democli@example.com
单个用户详情(/api/v1/user/<username>):
curl -s -b admin.jar http://gitproxy.local:8150/api/v1/user/reviewer
{"username":"reviewer","displayName":"","email":"reviewer@example.com","title":"","scmIdentities":{},"admin":false}
创建用户(POST /api/auth/create-user,管理员会话)。新建 dev1,先用临时口令创建:
CT=$(curl -s -b admin.jar -c admin.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -w '\nHTTP:%{http_code}\n' -b admin.jar -X POST http://gitproxy.local:8150/api/auth/create-user \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" \
-d '{"username":"dev1","password":"dev1temp123","email":"dev1@example.com"}'
{"message":"User created successfully","username":"dev1"}
HTTP:201
修改密码(POST /api/auth/change-password,本人会话)。模拟 dev1 首次登录后把临时口令换成演示口令:
CT=$(curl -s -c dev1.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -b dev1.jar -c dev1.jar -X POST http://gitproxy.local:8150/api/auth/login \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" \
-d '{"username":"dev1","password":"dev1temp123"}'
CT=$(curl -s -b dev1.jar -c dev1.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -b dev1.jar -X POST http://gitproxy.local:8150/api/auth/change-password \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" \
-d '{"currentPassword":"dev1temp123","newPassword":"q1w2e3r4"}'
{"message":"Password updated successfully"}
5.3 仓库域(/api/v1/repo)
仓库白名单清单:
curl -s -b admin.jar http://gitproxy.local:8150/api/v1/repo/ | python3 -c "import json,sys;[print(r['_id'], r['project']+'/'+r['name']) for r in json.load(sys.stdin)]"
JgcqA5axqbi0LcWa admin/hello-gitproxy
eoe5s1nmyjFFmN71 admin/second-repo
新增白名单仓库(POST /api/v1/repo/,_id 由服务端生成,proxyURL 自动拼装):
CT=$(curl -s -b admin.jar -c admin.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -w '\nHTTP:%{http_code}\n' -b admin.jar -X POST http://gitproxy.local:8150/api/v1/repo/ \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" \
-d '{"project":"admin","name":"api-demo","url":"https://gitea.local:3000/admin/api-demo.git"}'
{"project":"admin","name":"api-demo","url":"https://gitea.local:3000/admin/api-demo.git","users":{"canPush":[],"canAuthorise":[]},"dateCreated":"2026-10-26T04:21:31.146Z","lastModified":"2026-10-26T04:21:31.146Z","_id":"TvJVq0VVeXOPxsKQ","proxyURL":"http://gitproxy.local:8149","message":"created"}
HTTP:201
_id 为 TvJVq0VVeXOPxsKQ。给 admin 授推送权、给 reviewer 授审批权(PATCH,{"username": …}):
CT=$(curl -s -b admin.jar -c admin.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -b admin.jar -X PATCH http://gitproxy.local:8150/api/v1/repo/TvJVq0VVeXOPxsKQ/user/push \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" -d '{"username":"admin"}'
CT=$(curl -s -b admin.jar -c admin.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -b admin.jar -X PATCH http://gitproxy.local:8150/api/v1/repo/TvJVq0VVeXOPxsKQ/user/authorise \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" -d '{"username":"reviewer"}'
{"message":"created"}
{"message":"created"}
复核授权矩阵(GET /api/v1/repo/<_id>):
curl -s -b admin.jar http://gitproxy.local:8150/api/v1/repo/TvJVq0VVeXOPxsKQ
{"project":"admin","name":"api-demo","url":"https://gitea.local:3000/admin/api-demo.git","users":{"canPush":["admin"],"canAuthorise":["reviewer"]},"dateCreated":"2026-10-26T04:21:31.146Z","lastModified":"2026-10-26T04:21:47.904Z","_id":"TvJVq0VVeXOPxsKQ","proxyURL":"http://gitproxy.local:8149"}
回收与删除:DELETE /api/v1/repo/<_id>/user/authorise/reviewer 回收审批权,DELETE /api/v1/repo/<_id>/delete 删除整条白名单记录(两者回显均为 {"message":"created"});删除后清单复核,api-demo 已消失,仅剩 hello-gitproxy 与 second-repo。
5.4 推送域(/api/v1/push)
推送记录清单(返回数组,按时间倒序,含历史记录)。用脚本打印最新两条的状态四元组:
curl -s -b admin.jar http://gitproxy.local:8150/api/v1/push/ | python3 -c "
import json,sys
for p in json.load(sys.stdin)[:2]:
print(p['id'][:16], p['repoName'], '| authorised:',p['authorised'],'rejected:',p['rejected'],'canceled:',p['canceled'],'blocked:',p['blocked'])"
27243868d87ba1cb admin/hello-gitproxy | authorised: False rejected: False canceled: True blocked: True
2d13fe11cb713cad admin/hello-gitproxy | authorised: False rejected: True canceled: False blocked: True
单条详情 GET /api/v1/push/<id>,完整记录含提交明细(commitData)、diff 全文与检查步骤流水(steps)。步骤多、diff 长,用脚本把 steps 折叠为步骤名序列、剔除 diff,字段结构一目了然:
curl -s -b admin.jar http://gitproxy.local:8150/api/v1/push/e9bbecdd76b07e8e7759f33ee3d3efe3829adaf5d1a52d9886e85a58c7faf521 \
| python3 -c "import json,sys; d=json.load(sys.stdin); d['steps']=[s['stepName'] for s in d['steps']]; d.pop('diff',None); d['commitData']=[{k:c.get(k) for k in ('message','author')} for c in d['commitData']]; print(json.dumps(d,ensure_ascii=False,indent=1))" | head -40
{
"id": "e9bbecdd76b07e8e7759f33ee3d3efe3829adaf5d1a52d9886e85a58c7faf521",
"project": "admin",
"repoName": "hello-gitproxy",
"branch": "main",
"type": "commit",
"authorised": true,
"rejected": false,
"canceled": false,
"blocked": false,
"error": false,
"user": "admin",
"userEmail": "admin@example.com",
"commitData": [
{
"message": "docs: d1 api closed-loop test",
"author": "admin"
}
],
"steps": [
"parsePackFile",
"resolveUserFromToken",
"checkRepoInAuthorisedList",
"checkMessages",
"checkAuthorEmails",
"checkUserPushPermission",
"pullRemote",
"writePack",
"checkHiddenCommits",
"checkIfWaitingAuth",
"executeExternalPreReceiveHook",
"diff",
"gitleaks",
"scanDiff",
"authBlock",
"clearBareClone"
],
...
steps 就是六节回显里那些 remote: Checking … 的内部对应物:从解析包、身份解析、白名单/消息/邮箱/权限检查,到 diff 与密钥扫描,最后 authBlock 决定放行还是挂起审批。状态字段含义:
| 组合 | 含义 |
|---|---|
authorised: false, blocked: true, canceled: false, rejected: false | 待审批(默认态) |
authorised: true, blocked: false | 已批准,复推后落地 |
rejected: true, blocked: true | 已驳回(rejection.reason 带驳回理由与审批人) |
canceled: true, blocked: true | 推送人已自行取消 |
5.5 推送审批三个写端点
三个写端点的请求体与回显(均在六节闭环中实测):
| 端点 | 请求体 | 成功回显 |
|---|---|---|
POST /api/v1/push/<id>/authorise | {"params":{"attestation":[{"label":"…","checked":true},…]}} | {"message":"authorised <id>"} |
POST /api/v1/push/<id>/reject | {"reason":"…"}(缺 reason 返回 400) | {"message":"reject <id>"} |
POST /api/v1/push/<id>/cancel | 无 | {"message":"cancel <id>"} |
三条硬约束(实测):attestation 数组的 label 必须与 attestationConfig.questions 逐字一致,否则 400 Attestation is not complete;推送人审批自己发起的推送返回 User admin not authorised to approve pushes on this project(四眼原则);cancel 只能由推送人本人对未决推送调用。
六、git push 触发审批实测闭环
以下命令全部在演示工作机执行(工作机同样按部署篇配置了 /etc/hosts 与对 gitproxy.local:8149 的访问)。仓库 /root/work/hello-gitproxy 克隆自上游 Gitea(部署篇 4.8 节),GITEA_TOKEN 已按三节交互式录入。
6.1 推送入队(待审批)
cd /root/work/hello-gitproxy
echo "d1-api-loop-test $(date +%s)" > d1note.txt
git add d1note.txt && git commit -qm "docs: d1 api closed-loop test"
git push "http://admin:${GITEA_TOKEN}@gitproxy.local:8149/gitea.local:3000/admin/hello-gitproxy.git" main
实测回显(输出节选,行尾多空格略):
remote: Resolving user from token...
remote: Checking for empty branch...
remote: Checking repository is authorised...
remote: Checking commit messages...
remote: Checking author emails...
remote: Checking push permissions...
remote: Fetching remote repository...
remote: Writing pack data...
remote: Checking for hidden commits...
remote: Checking approval status...
remote: Running pre-receive hook...
remote: Computing diff...
remote: Scanning for secrets...
remote: Scanning diff contents...
remote: Requesting approval...
remote:
remote: GitProxy has received your push ✅
remote: 🔗 Shareable Link
remote: http://gitproxy.local:8150/dashboard/push/e9bbecdd76b07e8e7759f33ee3d3efe3829adaf5d1a52d9886e85a58c7faf521
To http://gitproxy.local:8149/gitea.local:3000/admin/hello-gitproxy.git
! [remote rejected] main -> main (approval required)
error: failed to push some refs to 'http://gitproxy.local:8149/gitea.local:3000/admin/hello-gitproxy.git'
提交被网关完整接收并进入审批队列(分享链接末段即推送 _id),上游尚未收到该提交。随后用五.1 节的登录流程建立 reviewer 会话。
6.2 批准与落地
CT=$(curl -s -b reviewer.jar -c reviewer.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -w ' HTTP:%{http_code}\n' -b reviewer.jar -X POST http://gitproxy.local:8150/api/v1/push/e9bbecdd76b07e8e7759f33ee3d3efe3829adaf5d1a52d9886e85a58c7faf521/authorise \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" \
-d '{"params":{"attestation":[{"label":"I have checked every commit in this push","checked":true},{"label":"I am authorised to make this push","checked":true}]}}'
{"message":"authorised e9bbecdd76b07e8e7759f33ee3d3efe3829adaf5d1a52d9886e85a58c7faf521"} HTTP:200
复核详情:authorised: true,attestation 记录了两项确认、审批人 reviewer 与审批时间戳。批准后复推同一分支:
git push "http://admin:${GITEA_TOKEN}@gitproxy.local:8149/gitea.local:3000/admin/hello-gitproxy.git" main
remote: Checking approval status...
remote: . Processing 1 references
remote: Processed 1 references in total
To http://gitproxy.local:8149/gitea.local:3000/admin/hello-gitproxy.git
757f8c7..e705760 main -> main
提交真正落到上游 Gitea(远端引用从 757f8c7 前进到 e705760)。
6.3 驳回(reject)
再推一个用于驳回的提交,然后 reviewer 带理由驳回:
echo "d1-reject-test $(date +%s)" > d1rej.txt
git add d1rej.txt && git commit -qm "docs: d1 reject loop test"
git push "http://admin:${GITEA_TOKEN}@gitproxy.local:8149/gitea.local:3000/admin/hello-gitproxy.git" main
# 新推送 _id:2d13fe11cb713cada5c8f3b2390b812a42437188f7420de6582eb4be79fdbec9
CT=$(curl -s -b reviewer.jar -c reviewer.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -w ' HTTP:%{http_code}\n' -b reviewer.jar -X POST http://gitproxy.local:8150/api/v1/push/2d13fe11cb713cada5c8f3b2390b812a42437188f7420de6582eb4be79fdbec9/reject \
-H 'Content-Type: application/json' -H "X-CSRF-Token: $CT" \
-d '{"reason":"变更未包含关联工单编号,请补充后再推送。"}'
{"message":"reject 2d13fe11cb713cada5c8f3b2390b812a42437188f7420de6582eb4be79fdbec9"} HTTP:200
复核详情(状态字段与驳回记录):
curl -s -b admin.jar http://gitproxy.local:8150/api/v1/push/2d13fe11cb713cada5c8f3b2390b812a42437188f7420de6582eb4be79fdbec9 \
| python3 -c "import json,sys; d=json.load(sys.stdin); print('rejected:',d['rejected'],'| blocked:',d['blocked']); print(json.dumps(d['rejection'],ensure_ascii=False))"
rejected: True | blocked: True
{"reason": "变更未包含关联工单编号,请补充后再推送。", "timestamp": "2026-10-26T04:24:26.321Z", "reviewer": {"username": "reviewer", "email": "reviewer@example.com"}}
6.4 驳回后重推(仍被拦截)
带着被驳回的同一段历史再次推送,网关仍指向同一条审批记录、继续拦截:
remote: Checking approval status...
remote: . Processing 1 references
remote: Processed 1 references in total
remote: http://gitproxy.local:8150/dashboard/push/2d13fe11cb713cada5c8f3b2390b812a42437188f7420de6582eb4be79fdbec9
! [remote rejected] main -> main (approval required)
error: failed to push some refs to 'http://gitproxy.local:8149/gitea.local:3000/admin/hello-gitproxy.git'
结论:驳回不靠「重试」翻案,必须按驳回意见修改、形成新提交后再推(6.5 节的新提交即产生全新推送记录)。
6.5 取消(cancel,推送人本人)
推送人可以撤回自己的待审批推送。新推一个提交(产生 27243868d87ba1cb… 记录),然后 admin 本人取消:
CT=$(curl -s -b admin.jar -c admin.jar http://gitproxy.local:8150/api/auth/csrf-token | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -w ' HTTP:%{http_code}\n' -b admin.jar -X POST http://gitproxy.local:8150/api/v1/push/27243868d87ba1cbb1857d1e8441fbbe9f6555571e28e549dd4af93ee2719384/cancel \
-H "X-CSRF-Token: $CT"
{"message":"cancel 27243868d87ba1cbb1857d1e8441fbbe9f6555571e28e549dd4af93ee2719384"} HTTP:200
复核:canceled: true。至此「待审批 → 批准落地 / 驳回拦截 / 自行取消」三种走向全部闭环。
七、推送人 CLI(@finos/git-proxy-cli)
7.1 定位与安装
@finos/git-proxy-cli v2.3.0 是推送人侧的命令行工具(npm install -g @finos/git-proxy-cli 后获得 git-proxy-cli 命令),把六节的 REST 调用封装成「登录 → 列表 → 审批」的固定动作,会话 Cookie 落在当前目录 git-proxy-cookie 文件里。
7.2 命令清单
git-proxy-cli --help
git-proxy-cli <command>
Commands:
git-proxy-cli authorise authorise a push
git-proxy-cli cancel cancel a push
git-proxy-cli config check config
git-proxy-cli login log in to GitProxy
git-proxy-cli logout log out of GitProxy
git-proxy-cli ls list pushes awaiting approval
git-proxy-cli reject reject a push
git-proxy-cli reload-config reload the GitProxy config
git-proxy-cli createuser create a user
Options:
--help Show help [boolean]
7.3 网关地址
CLI 从两个环境变量拼装基地址:GIT_PROXY_UI_HOST(默认 http://localhost)与 GIT_PROXY_UI_PORT(默认 8080)。指向本环境:
export GIT_PROXY_UI_HOST=http://gitproxy.local GIT_PROXY_UI_PORT=8150
7.4 CSRF 拦截实测
csrfProtection: true 时,CLI 的 login 直接被 403 拒绝(CLI 未实现 CSRF Token 获取流程):
git-proxy-cli login --username admin --password q1w2e3r4
Error: Login 'admin': '403'
这与部署篇 FAQ Q6、配置参数详解篇 5.2 节的结论一致。要实际使用 CLI 审批,需要临时关闭 csrfProtection 并重启,且 CLI 的 authorise 固定提交内置问卷 label Authorising via GitProxy CLI——attestationConfig.questions 的第一项必须逐字改为该值(改法与恢复见配置参数详解篇 5.7 节)。
7.5 选型建议
交互式审批日常可用管理台网页完成;自动化与脚本统一走 REST API(5 节):CSRF、会话、问卷 label 全部可控,不依赖 CLI 的硬编码行为。CLI 适合给推送人提供最小化的命令行体验。
八、注意事项
- CSRF Token 一次性:每次写操作前重新
GET /api/auth/csrf-token,复用旧 Token 必得 401CSRF token mismatch(5.1 节实测); - 会话有效期:
sessionMaxAgeHours: 12(本环境取值),过期后所有请求重新走登录流程;登出后 Cookie 立即失效(5.1 节 401 实测); - 限流:管理台 API 60 秒 1000 次(
rateLimit),超限返回 429 并携带X-RateLimit-*与Retry-After头(压测形态见配置参数详解篇 5.3 节); - 401 与 403 的语义:缺 Token/Token 失配是 401(JSON 报文);带 Token 但会话未建立(如 CLI 直连 login)是 403;权限不足有专属报文(如推送人审批自己发起的推送返回
User admin not authorised to approve pushes on this project,5.5 节); - Gitea Token 作用域:推送凭据建议
read:user+write:repository——网关要从 Token 反查用户身份(Resolving user from token...),只给write:repository可能卡在身份解析;Token 失效时推送表现为认证失败,重签后恢复; - 生产自动化别用 Cookie 会话:给脚本长期用
POST /api/auth/login维持会话不如启用apiAuthentication(JWT)方案,键位见配置参数详解篇 5.14 节; - 不要用本篇演示口令:
q1w2e3r4仅为系列演示值,生产环境按部署篇的安全清单替换。
九、常见问题(FAQ)
Q1:所有 POST 都报 CSRF token mismatch 或 CSRF token missing?
没带 X-CSRF-Token 头或复用了旧 Token。按 5.1 节模式「先取 Token → 立即随写请求提交」,每个写请求都取新的。
Q2:POST /api/auth/login 返回 403 还是 401?
403 且响应是 HTML 报错页:请求根本没带 X-CSRF-Token 头(lusca 中间件直接拒绝,5.1 节);401 且响应是纯文本 Unauthorized:CSRF 头正确但口令不对(实测),核对部署篇 4.7 节的账号初始化步骤。
Q3:GET /api/v1/config 返回 HTML 而不是配置 JSON?
/api/v1/config 只有五个只读子端点(attestation/scmProviders/contactEmail/urlShortener/uiRouteAuth),访问其他路径会落到管理台页面兜底路由。完整配置以配置文件与 node dist/index.js -v -c 校验为准(4.3 节)。
Q4:CLI 全家桶都报 403?
csrfProtection: true 拦的,见 7.4 节;临时关闭并改完问卷 label 才能走通 CLI 审批,用完记得恢复。
Q5:git push 报 Authentication failed?
推送凭据是「GitProxy 用户名 + Gitea Token」,检查 Token 是否失效、作用域是否含 read:user(三节/注意事项 5)。
Q6:批准后复推还是 approval required?
先确认调的是正确的推送 _id(分享链接末段),再用 GET /api/v1/push/<id> 看 authorised 字段。若仍是 false,检查审批人是否在仓库 canAuthorise 列表、attestation label 是否逐字一致。
Q7:审批人能看到别人的推送明细吗?
推送域读取端点要求登录会话;审批人通过管理台或 GET /api/v1/push/<id>(reviewer 会话)都能查看待审批明细,但只有 canAuthorise 名单内的人能执行 authorise/reject。
十、参考链接
- GitProxy 官方文档(API 与 CLI):https://finos.github.io/git-proxy/
- GitProxy 源码(服务路由与 CLI):https://github.com/finos/git-proxy
- GitProxy v2.3.0 Release:https://github.com/finos/git-proxy/releases/tag/v2.3.0
- 本系列姊妹篇:《GitProxy 2.3 介绍与选型指南》、《GitProxy 2.3 Docker Compose 部署指南》、《GitProxy 2.3 配置参数详解》