Files
xmz7891 d60dfcf671 发布脚本:提前检查 EzHub 令牌写权限
Gitea 令牌可以只给读权限。只读令牌能读仓库、能列发行版,
看起来一切正常,但一推代码就 403、一建发行版也 403。

加了 check_ezhub_scope():开头就用一个**无副作用**的探针确认权限
(对不存在的发行版发 DELETE —— 403 说明缺 write:repository,
404 说明权限过了只是资源不存在),缺权限就立刻停下并给出
明确的修复指引,不让它走到一半才炸。

文档里也写清了这个坑。
2026-10-07 12:25:12 +08:00

88 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
r'''判定 EzHub 令牌到底有没有写权限(无副作用)。
方法:对一个**不存在的**资源发写请求。
* 令牌没有写权限 -> 服务端先拦权限,返回 403
* 令牌有写权限 -> 通过权限检查,然后发现资源不存在,返回 404
所以 403 / 404 这个差别就能说明问题,而且不会真的改到任何东西。
'''
from __future__ import annotations
import json
import sys
import urllib.error
import urllib.request
TOKEN = sys.argv[1] if len(sys.argv) > 1 else ""
if not TOKEN:
print(" 用法: python probe_token.py <令牌>")
raise SystemExit(1)
BASE = "https://git.261826.xyz/api/v1"
HEAD = {"Authorization": "token " + TOKEN, "User-Agent": "ykxmz-probe"}
def probe(method: str, path: str, payload: dict | None = None,
label: str = "") -> int:
data = json.dumps(payload).encode() if payload else None
headers = dict(HEAD)
if data:
headers["Content-Type"] = "application/json"
req = urllib.request.Request(BASE + path, data=data, method=method,
headers=headers)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
print(" %-10s %-46s -> %s" % (method, path, resp.status))
return resp.status
except urllib.error.HTTPError as exc:
body = exc.read().decode("utf-8", "replace")[:110]
print(" %-10s %-46s -> %s %s"
% (method, path, exc.code, body))
return exc.code
except Exception as exc: # noqa: BLE001
print(" %-10s %-46s -> 异常 %s" % (method, path, exc))
return 0
print(" 一、读权限(应该 200)")
probe("GET", "/user")
probe("GET", "/repos/xmz/ykxmz")
print()
print(" 二、写权限判定(对不存在的资源写)")
print(" 403 = 没写权限;404 = 有写权限(只是资源不存在)")
del_code = probe("DELETE", "/repos/xmz/ykxmz/releases/99999999")
print()
patch_code = probe("PATCH", "/repos/xmz/ykxmz/releases/99999999",
{"body": "probe"})
print()
post_code = probe("POST", "/repos/xmz/ykxmz/releases",
{"tag_name": "", "name": "", "body": ""})
print()
print(" 三、结论")
if del_code == 404 or patch_code == 404:
print(" ✓ 令牌**有写权限**(返回 404 说明权限过了,只是资源不存在)")
print(" -> HTTPS push 的 403 是另一个原因,需要再查")
elif del_code == 403 or patch_code == 403:
print(" ✗ 令牌**没有写权限**(403)")
print(" -> 需要重新生成令牌,勾上 write:repository")
else:
print(" ? 结果不明确:DELETE=%s PATCH=%s POST=%s"
% (del_code, patch_code, post_code))
print()
print(" 四、顺带看一下令牌信息")
try:
req = urllib.request.Request(BASE + "/user", headers=HEAD)
with urllib.request.urlopen(req, timeout=30) as resp:
for name in ("X-Oauth-Scopes", "X-Oauth-Client-Id"):
value = resp.headers.get(name)
if value:
print(" %s: %s" % (name, value))
me = json.loads(resp.read().decode())
print(" 用户: %s (id=%s, admin=%s)"
% (me.get("login"), me.get("id"), me.get("is_admin")))
except Exception as exc: # noqa: BLE001
print(" 读取失败: %s" % exc)