Files
ykxmz/_build/fix_release_ip_leak.py
xmz7891 0ad3f648c6 修上一轮清理留下的副作用:占位符把运维脚本弄连不上了
上一个提交把仓库里的服务器 IP 换成了占位符,但**那些脚本本身要用这个 IP
去连服务器** —— 换掉之后它们就跑不起来了。这个提交把取值方式理清楚。

== 取值统一走 _build/lssh.py ==

    YKXMZ_LS_HOST 环境变量
    或 _build/.lightsail_host(一行 IP,已 gitignore)
    都没有就报错,并告诉你怎么设

十个运维脚本改成 `from lssh import ... HOST as LS_HOST`,
公开仓库里一个具体地址都不留。

== 顺带修的两个自己造的 bug ==

  * 用正则往 `from lssh import ...` 后面追加东西时,
    追加到了行尾的 `# noqa: E402` **注释里面** ——
    十处导入全是废的,脚本一跑就 NameError。
    改成先剥掉注释、拼好导入、再把 noqa 加回去。

  * 同一个正则还把 `from lssh import HOST as LS_HOST` 加进了
    **lssh.py 自己**,造成自我导入。

教训:**正则批量改导入语句很危险**(注释、行尾、顺序都能坑到),
这种地方宁可逐个 edit。

== 为什么要重建产物 ==

docs/AFTER-INSTALL.txt 会被打进服务端 zip,而它上一轮改过
(去掉了写死的旧管理员密码)—— 不重打的话发出去的还是旧的。

重打后确认:三个产物里都没有旧密码、没有服务器 IP。

== 验证 ==

    全量回归退出码 0,41 个阶段全 PASS
    603 个 Python 文件语法通过
    ykxmz-agent / server / watch 三个产物扫描干净
    提交前泄漏闸门通过
2026-10-09 00:02:32 +08:00

140 lines
4.8 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'''撤掉 Gitee 发行版介绍里泄漏的公网 IP。
== 用户报的 ==
"那个发行版的介绍里,服务器公网 IP 地址暴露出去了"
来源:发布脚本(gitee_release.py / release_all.py)把
_build/CHANGELOG.md 当"更新说明"传给 Gitee 建发行版,
而 CHANGELOG 的 2.1.3 那节里写了 <源站IP>。
工作区那边已经清了(_build/scrub_server_ip.py),
但**已经发出去的发行版介绍还在 Gitee 上**,得用 API 改回去。
== 接口 ==
PATCH /api/v5/repos/{owner}/{repo}/releases/{id}
参数:access_token + body(新的发行版介绍)
== 顺带检查所有发行版 ==
不只 v2.1.3 —— 从 2.1.0 起我就在"把 CHANGELOG 当更新说明",
而 2.1.0/2.1.1 那几节也提到过服务器。全部扫一遍、有 IP 的都改掉。
'''
from __future__ import annotations
import json
import sys
import urllib.parse
import urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
# ⚠ 这个脚本要"在所有发行版介绍里找这个 IP",所以它必须知道 IP。
# 但**不能在源码里写死** —— 写了就等于把 IP 又发到公开仓库里,
# 正是这个脚本要防的事。
# 从 lssh 取(那里会读环境变量 YKXMZ_LS_HOST 或
# _build/.lightsail_host,后者已 gitignore)。
sys.path.insert(0, str(Path(__file__).resolve().parent))
from lssh import HOST as IP, HOST as LS_HOST # noqa: E402
DOMAIN = "yk.xxmxxs.top"
OWNER_REPO = "xmz7891/ykxmz"
def api(url: str, data: bytes = None, method: str = None) -> tuple:
req = urllib.request.Request(url, data=data, method=method)
req.add_header("User-Agent", "ykxmz-release-fix")
if data is not None:
req.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(req, timeout=60) as r:
return r.status, json.loads(r.read().decode("utf-8"))
except urllib.error.HTTPError as exc:
return exc.code, exc.read().decode("utf-8", "replace")[:300]
def main() -> int:
token_file = ROOT / "_build" / ".gitee_token"
if not token_file.is_file():
print(" ✗ 找不到 _build/.gitee_token")
return 1
token = token_file.read_text(encoding="utf-8").strip()
print("=" * 62)
print(" 撤掉 Gitee 发行版介绍里的公网 IP")
print("=" * 62)
print()
print(" ── 1. 列出所有发行版 ──")
code, data = api(
"https://gitee.com/api/v5/repos/%s/releases"
"?access_token=%s&per_page=60" % (OWNER_REPO, token))
if code != 200:
print(" ✗ 列不出来: %s" % data)
return 1
print(" 共 %d 个发行版" % len(data))
print()
print(" ── 2. 逐个检查 body,有 IP 的改掉 ──")
fixed = 0
for rel in data:
tag = rel.get("tag_name", "?")
rid = rel.get("id")
body = rel.get("body") or ""
if IP not in body:
print(" %-10s 干净" % tag)
continue
n = body.count(IP)
new_body = body.replace(IP, DOMAIN)
print(" %-10s ⚠ 有 %d 处 -> 改掉" % (tag, n))
# ⚠ 两个坑:
#
# 1. 必须用 **JSON**。第一版 urlencode 拼了 data,但 api()
# 见 data 非空就声明 Content-Type: application/json ——
# 内容和声明不一致,Gitee 回 400(一页 HTML 错误页)。
#
# 2. **tag_name 和 name 必须一起传**,即使不改它们。
# 漏了会报 {"messages":["tag_name is missing",
# "name is missing"]}。
# (PATCH 语义上应该允许只改 body,但 Gitee 的实现要求
# 把标识字段带上 —— 那就带上。)
payload = json.dumps({
"access_token": token,
"tag_name": tag,
"name": rel.get("name") or tag,
"body": new_body,
}).encode("utf-8")
code2, resp = api(
"https://gitee.com/api/v5/repos/%s/releases/%s"
% (OWNER_REPO, rid), data=payload, method="PATCH")
if code2 == 200:
print(" ✓ 已更新")
fixed += 1
else:
print(" ✗ 更新失败 (%s): %s" % (code2, resp))
print()
print(" ── 3. 复查 ──")
code, data = api(
"https://gitee.com/api/v5/repos/%s/releases"
"?access_token=%s&per_page=60" % (OWNER_REPO, token))
still = [r.get("tag_name") for r in data
if IP in (r.get("body") or "")]
if still:
print(" ⚠ 还有: %s" % ", ".join(still))
else:
print(" ✅ 所有发行版介绍里都没有这个 IP 了")
print()
print(" 改了 %d 个发行版" % fixed)
return 0
if __name__ == "__main__":
sys.exit(main())