wangjia
b584188ce2
fix(ci/site): 用 ! Content-Security-Policy 删官网 CSP(CF _headers 叠加,浏览器取交集)
...
Deploy Site / deploy-site (push) Successful in 4m36s
上一版判断错了:CF Pages _headers 不是'首个匹配生效',而是【叠加下发】——/* 和
/user/* 都匹配 /user/,两条 CSP 都发,浏览器对多条 CSP 取交集(最严)→ 官网严格
CSP 的 style-src(无 unsafe-inline)/connect-src('self')赢,用户中心内联样式被拦、
连 API 被拦 → 裸奔 + 登录失败。正解:/user/* 里 先删掉
/* 继承的官网 CSP,再设用户中心自己的(排 /* 之后,先加后删)。其余安全头沿用 /*。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 22:25:36 +08:00
wangjia
60cd28e085
fix(ci/site): _headers 里 /user/* 须排在 /* 之前(CF 首个匹配 header 生效)
...
Deploy Site / deploy-site (push) Successful in 4m3s
用户中心 /user/ 页裸奔根因:CF Pages _headers 对同一 header 取【首个匹配规则】值,
而 combine-site 原把 /user/* 追加在官网 /* 之后 → /user/ 命中在前的官网严格 CSP
(style-src 无 unsafe-inline),用户中心的大量内联样式被拦、连 API 的 connect-src
也被收窄 → 样式全丢。改为把 /user/* 规则前置到官网 /* 之前,用户中心 CSP 才生效。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 21:56:29 +08:00
wangjia
11ca7531a3
ci: flutter build 前显式 pub get + 重试(防 pub.flutter-io.cn 被 GFW 抖断)
...
Deploy Client / build-android (push) Successful in 1m46s
Deploy Client / build-windows (push) Successful in 1m55s
Deploy Client / build-macos (push) Successful in 3m40s
Deploy Client / build-ios (push) Successful in 3m28s
Deploy Client / release-deploy (push) Successful in 2m14s
iOS build 曾因 flutter build 内隐式 pub get 拉 google_fonts 时 pub.flutter-io.cn
socket error(exit 69)而失败。_env.sh 加 flutter_pub_get_retry(5 次重试),四个
compile 脚本在 flutter build 前显式预取,成功后 build 命中缓存不再拉网,减少偶发
网络失败。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 20:25:01 +08:00
wangjia
aaffe85a4f
fix(ci/windows): 同步 Flutter app 版本到 tag(原卡在 pubspec 1.0.48)
...
compile-windows 此前只 sed Inno 安装器 MyAppVersion,没改 Flutter pubspec 版本,
导致 Windows 包内 package_info 永远是 committed 的 1.0.48 → 设置页显示旧版 +
自动更新永远判"有新版"。补上 build number 计算 + sed 复制后的 pubspec.yaml
(GNU sed,windows runner),与 android/macos 对齐。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 19:05:31 +08:00
wangjia
4940278ea5
feat(migrate): 用户中心迁到 pangolin.yanmeiai.com/user/ + 域名配置化
...
Deploy Server / deploy-server (push) Successful in 2m55s
Deploy Site / deploy-site (push) Successful in 2m41s
Deploy Client / build-windows (push) Successful in 1m47s
Deploy Client / build-android (push) Successful in 7m39s
Deploy Client / build-macos (push) Successful in 3m40s
Deploy Client / build-ios (push) Successful in 4m48s
Deploy Client / release-deploy (push) Successful in 2m25s
原独立子域 app.yanmeiai.com → 主站子路径 /user/(用户选停用旧域名):
- 域名配置化(去硬编码):客户端 kWebUserCenterBaseUrl 收进 api_config.dart
(dart-define 可覆盖);官网 site.ts、服务端 CORS_ORIGINS 本就是配置
- 用户中心 next.config basePath=/user;layout.tsx 的 /colors_and_type.css 手动
拼 basePath(public 根绝对资源不自动加前缀,否则 404)
- CI 合并部署:compile-site + compile-usercenter + combine-site(用户中心并入
dist/user/ + _headers 按 /user/* 分域:官网严格 CSP,用户中心 unsafe-inline+
connect-src https)→ 单次部署 pangolin-site;删独立 pangolin-usercenter 部署
- 服务端 CORS 默认 origin app.yanmeiai.com → pangolin.yanmeiai.com(+ 测试)
- 客户端 web_launch 走新址 → 随 client-v1.0.62;go test CORS 过、flutter analyze 净
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 17:33:22 +08:00
wangjia
f9a87a9993
ci(site): deploy-site 增补用户中心构建+部署(补 CI 缺口)
...
Deploy Site / deploy-site (push) Successful in 3m42s
用户中心此前无 CI 部署(手动 wrangler),漂移风险。现纳入 site-v* 发版:
- scripts/ci/compile-usercenter.sh:next build → out/,⚠️ 内置 NEXT_PUBLIC_API_MODE=http
+ NEXT_PUBLIC_API_DOMAINS=https://api.yanmeiai.com (不设默认 mock=假数据,是个坑)
- scripts/ci/deploy-usercenter.sh:wrangler pages deploy → pangolin-usercenter
(app.yanmeiai.com)
- deploy-site.yml 追加两步,官网+用户中心同一 tag 发,CF token/account 走全局 secret
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 13:37:31 +08:00
wangjia
6ce67176da
fix(ci/macos): 构建后从 WORK 目录 embed 描述文件(xcodebuild 会清 PROF_DIR)
...
Deploy Client / build-android (push) Successful in 1m39s
Deploy Client / build-windows (push) Successful in 1m53s
Deploy Client / build-macos (push) Successful in 3m43s
Deploy Client / build-ios (push) Successful in 3m5s
Deploy Client / release-deploy (push) Successful in 2m7s
build-macos 失败:flutter build macos 期间 xcodebuild 修剪
~/Library/Developer/Xcode/UserData/Provisioning Profiles,把构建前装进去的
Developer ID 描述文件删掉,构建后 inside-out 重签时从该目录 cp 扑空
(cp: <uuid>.provisionprofile: No such file → exit 1)。改为从 mktemp 的 WORK
目录复制原始 .provisionprofile(xcodebuild 不碰),幂等可靠。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 11:27:50 +08:00
wangjia
4e8d928350
feat(ci): macOS + iOS 客户端 CI 脚本(照 jiu + 系统扩展)+ 自动更新 manifest 推送接线
...
Deploy Client / build-android (push) Failing after 1m16s
Deploy Client / build-macos (push) Failing after 3s
Deploy Client / build-ios (push) Successful in 2s
Deploy Client / build-windows (push) Has been cancelled
Deploy Client / release-deploy (push) Has been cancelled
compile-macos.sh(Developer ID 签名+公证+staple, 2 描述文件+libbox 重建+CFBundleVersion 递增,
早期 fail-fast 缺 secret 不浪费构建)、compile-ios.sh(TestFlight, 缺 secret 优雅跳过)。
deploy-client.yml 加 build-macos/build-ios(runs-on mac, continue-on-error+release-deploy 不 needs
它们 → 不拖挂 android/windows)。release-client.sh 兼容自动更新 manifest 推送 + macos zip。
+ url_launcher 的 macos/windows 生成插件注册。代码就绪, 待 Apple secret 才能真跑 macOS/iOS。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 00:20:00 +08:00
wangjia
7b1f49c182
fix(ci): compile-windows 传 ISCC 用 Windows 路径(cygpath)
...
Deploy Client / build-android (push) Successful in 1m38s
Deploy Client / build-windows (push) Successful in 8m29s
Deploy Client / release-deploy (push) Failing after 6s
首个 Windows CI 失败:ISCC 'Unknown option: /c/pangolin-build/.../pangolin.iss'——
ISCC 是原生 Windows 程序,MSYS /c/... 路径被当成选项。用 cygpath 转 C:\... 再传。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 22:31:40 +08:00
wangjia
2698116696
feat(ci): 客户端 CI 脚手架(Android+Windows, 照 jiu)——起草+Android 本地验证
...
- compile-android.sh: 建 libbox.aar + split-per-abi 取 arm64-v8a(~82MB, 避 232MB
universal) + release 签名(RELEASE_KEYSTORE/KEY_PASSWORD)。本地已验证构建通过、
libbox.so 打进 APK。
- compile-windows.sh: 复用 client/windows/installer/pangolin.iss(Inno Setup),不签名。
- release-client.sh / deploy-client.sh: 复用 pangolin lib-forgejo/lib-ssh,传 Gitea
release + 部署最新到 pangolin1:/var/lib/pangolin/downloads(仅留最新)。
- deploy-client.yml: client-v* tag → build-android(mac)+build-windows(windows) → release-deploy(mac)。
- build.gradle: 补 release 签名 config(读 key.properties, 缺则回退 debug)。
- 待确认: keystore alias/密码(见脚本 TODO);runner 需提到 user 级;服务器 /downloads + 官网链接下一步。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 19:40:34 +08:00
wangjia
973c2c021b
fix(ci): 网络操作加超时(runner 长任务 ~14min 无日志崩溃 → 快失败可诊断)
...
Deploy Server / deploy-server (push) Successful in 3m24s
Setup Go 下载 + Forgejo GET/create/upload 的 curl 原本无 --max-time,网络停顿即
无限挂起(疑似 runner 长任务崩溃且不留日志的根因)。加 --max-time(+GET/下载 retry),
让停顿在超时内快失败并留下日志,而非静默 14 分钟后崩。POST 不 retry(避免重复建/传)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 18:43:59 +08:00
wangjia
f1950ffb6f
fix(ci): release-server 首次实跑修复 + go 工具链 sha256 pin
...
Deploy Server / deploy-server (push) Failing after 13m45s
- lib-forgejo/release-server: 5 处 read -r X < file 在 set -e 下遇无结尾换行的
EOF 会返回 1 静默中止(ver_from_tag printf 无换行、curl -w http_code 无换行);
逐处加 || true 容错(值已赋)。
- lib-forgejo: 空数组 ${FORGEJO_CURL_TLS[@]} 在 set -u 下老 bash 报 unbound;
改 empty-safe 展开(可移植 + 本地可测)。
- deploy-server.yml: Setup Go 加 sha256 校验(供应链完整性, 防镜像篡改注入工具链)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 18:04:51 +08:00
wangjia
4d67a90659
fix(ci): deploy-server 隧道 healthcheck 改非致命(本地 healthz 才是权威闸)
...
Deploy Server / deploy-server (push) Failing after 22s
隧道 /healthz 依赖 cloudflared/CF 边缘,与本次二进制是否健康是两回事;
CF 边缘抖动或隧道尚未 provision 不应判整次部署失败。改为失败仅告警。
(最终 whole-branch review 的 Minor A 决议)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 16:59:52 +08:00
wangjia
06ba76e22b
feat(deploy): 8080 收 loopback + 关 8080 防火墙 + 健康检查改本地/隧道(退役明文控制口)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 16:47:32 +08:00
wangjia
f8e870fd6a
fix(ci): backup 大小 sanity 阈值 50k→1k(小库压缩后 <50k 被误删)
...
远端 .backup 出的库 gzip 后可能 <50KB,原 >50k 检查把有效备份当'异常小'删了。
空 gzip 仅 ~20 字节,>1k 足以区分空/断流与有效备份。
2026-07-06 15:34:18 +08:00
wangjia
e557a94ed0
fix(ci): lib-ssh 加 IdentitiesOnly+BatchMode(修 Too many auth failures)
...
CI ssh 到 pangolin1 报 Too many authentication failures + 回落密码提示:ssh 把
容器默认/agent key 也一并递上,撞 MaxAuthTries。加 IdentitiesOnly=yes 只用 -i key,
BatchMode=yes 纯非交互。影响 deploy-server / backup 等所有走 lib-ssh 的部署。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-06 15:05:44 +08:00
wangjia
e1a17acbe4
feat(ci): SQLite 每日备份到 NAS(异地容灾,#26/F2)
...
backup-db.sh:ssh pangolin1 → sqlite3 online .backup 取 WAL 一致快照 + 远端
integrity_check → gzip 流回 → 存 NAS /volume1/docker/backups/pangolin,保留 30 天。
backup.yml:每日 02:00(北京)cron + 手动,ubuntu-latest,复用 DEPLOY_SSH_KEY,
Telegram 通知。异地=家里 NAS≠VPS 机房。不在 pangolin1 装/常驻任何东西。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-06 14:55:11 +08:00
wangjia
3efd67297e
ci(server): 编译/测试直接在 runner 跑,去嵌套 docker(修 DinD;go 工具链自动下载)
...
compile-backend/test.sh 原在 golang:1.25 容器里跑,job 容器内 $PWD 在宿主不存在
→ DinD 挂载失败。改直接跑;go.mod 要求 1.25.10,靠 Go 工具链经 goproxy.cn 自动拉取。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-06 14:40:09 +08:00
wangjia
673914783d
refactor(ci): 官网部署改用 Cloudflare Pages(替代 rsync 到 pangolin1)
...
节点 :443 被 sing-box(VPN 数据面)占用,CF 免费套餐回源只能打 :80/:443、改端口需
Enterprise —— 故官网改由 CF Pages 托管(项目 pangolin-site,自定义域 pangolin.yanmeiai.com),
纯静态、全程 HTTPS、_headers/CSP 自动生效、不落 VPS、彻底无 :443 冲突。
deploy-site.sh 改为 wrangler pages deploy(需 CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID
Gitea secret);deploy-site.yml deploy 步骤在 node:20 容器内跑 wrangler。lib-ssh 仍供服务端部署用。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-06 09:59:58 +08:00
wangjia
443d4e3a11
feat(ci): test.sh(go test / flutter test)
...
Add scripts/ci/test.sh <server|client>: server runs `go test ./...`
inside golang:1.25 (mirrors ci.yml's go-server job docker invocation +
gomod/gobuild caches + GOPROXY from _env.sh); client runs `flutter test`
inside ghcr.io/cirruslabs/flutter:stable (mirrors ci.yml's flutter-client
job's pub-cache mount + test dirs). Wired into deploy-server.yml's Test
step already added in Task 4. Registers the script in ci.yml's shellcheck
file list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 00:37:48 +08:00
wangjia
0825170044
fix(ci): 服务端流水线注入加固(tag 校验/JSON 转义/workflow env)+ gitignore server/out
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 00:33:47 +08:00
wangjia
4fb3fe3fee
feat(ci): 服务端 server-v* 编译+release+部署(备份/迁移/回滚,复用 lib-ssh/lib-forgejo)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-06 00:24:18 +08:00
wangjia
91d1355721
fix(ci): 部署脚本 —— 私钥清理 trap 前移 + rsync 空目录守卫 + 主机密钥 accept-new(评审 Critical/Important)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-06 00:17:37 +08:00
wangjia
9bac5c8dcb
feat(ci): 官网 site-v* 构建+部署脚本(compile-site/deploy-site/lib-ssh/workflow)
...
- scripts/ci/compile-site.sh: node:20 容器内构建 web/website(Astro),
SITE_URL 注入 canonical 域名 https://pangolin.yanmeiai.com 。
- scripts/ci/lib-ssh.sh: 新增共享 setup_ssh/teardown_ssh(写临时私钥+
known_hosts),供 site 与后续 server 部署复用;目标写死 IP 103.119.13.48
(runner 无法解析用户本机 ~/.ssh/config 的 pangolin1 别名)。
- scripts/ci/deploy-site.sh: rsync dist/ 到 pangolin1
/var/www/pangolin-site/,root 部署。
- .gitea/workflows/deploy-site.yml: site-v* tag + workflow_dispatch 触发,
concurrency 组 deploy-site 防并发。
- .gitea/workflows/ci.yml: shellcheck 列表纳入三个新脚本。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 00:10:53 +08:00
wangjia
ff8fc36726
fix(ci): lib-forgejo TLS 校验默认开启,-k 改显式 opt-in(安全)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-05 23:55:56 +08:00
wangjia
b8343a8788
feat(ci): scripts/ci 基座(_env/lib-forgejo/notify)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-05 23:49:59 +08:00
wangjia
2c804d4ebf
fix(scripts): local_test.sh 对齐当前 macOS 架构(sysext 标识符名 + 静态 libbox)
...
发版脚本停留在旧「嵌入 Libbox.framework」架构,与现工程漂移两处、导致 sign 失败:
- sysext bundle 名 = 标识符 com.pangolin.pangolin.PacketTunnel.systemextension
(PRODUCT_NAME,见 CLAUDE.md),非短名 PacketTunnel.systemextension。
- libbox 现「只 Link 不 Embed」静态进 sysext 二进制,sysext 内已无独立
Libbox.framework;删掉对不存在 framework 的签名,签 sysext bundle 即覆盖。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-02 11:11:05 +08:00
wangjia
002eea7562
build(scripts): build-libbox apple 按平台分发产物,避免覆盖另一端 Frameworks
...
只编某一平台时(apple macos / apple ios),产出的 xcframework 只含该平台 slice,
不能覆盖到另一平台的 client/*/Frameworks(否则那端 build 缺 slice)。改为:
空(全 Apple)→ macos+ios 都放;macos→只 macos;ios→只 ios。
本次 iOS 打包已验证只部署到 client/ios/Frameworks。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-01 09:37:09 +08:00
wangjia
b23377acde
build(scripts): 各端 libbox 构建脚本修正 + 自动部署产物
...
排查 Android 打包"libbox.aar not found / Unresolved reference nekohasekai"踩坑:
- scripts/build-libbox.sh:
· 构建后自动部署产物到工程引用位置(android→app/kernel/dist/android/libbox.aar;
apple→client/{macos,ios}/Frameworks/Libbox.xcframework),不再留 /tmp 让人手动拷
· android 自动挑 NDK ≥28(未设 ANDROID_NDK_HOME 时):官方 build_libbox 拉 cronet-go,
其 libcronet.a 在 NDK 27 lld 链接报 unknown relocation(315)失败
· 头注释补全前置(NDK≥28 / JDK17 / gomobile 入 PATH)与产物路径
- app/kernel/build-android.sh:补 -javapkg io.nekohasekai —— 缺它产出默认包名 `libbox`,
与 Kotlin 的 io.nekohasekai.libbox 对不上、APK Kotlin 编译失败
- build.gradle:注释指明两条构建途径 + 包名必须 io.nekohasekai.libbox
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-01 07:53:35 +08:00
wangjia
97c0fdbbad
test(macos): local_test.sh 加 killswitch fail-closed 漏测子命令
...
ks-baseline:VPN 断开下记录真实公网 IP 基线
ks-test:VPN 连接(killswitch 开)下 sudo 杀扩展进程,在 on-demand 重连
窗口内反复探 IP —— 任何一次拿到真实 IP 即判泄漏(FAIL),全程被阻断/
仅隧道 IP 即 fail-closed 生效(PASS);随后验 on-demand 自愈
ks-status:看 VPN 状态 + 统一日志里 killSwitch/includeAllNetworks 打点
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-01 00:01:51 +08:00
wangjia
63bb31066f
test(ci): 闸1 接缝脚手架 new-seam.sh(支柱1:让对的写法成默认)
...
预防式闸:一条命令生成「接口 + Impl + Fake + Riverpod provider + flow-test 桩」,
外部依赖从一开始就藏接口后、可注入、自带 Fake、可测——把支柱1 变成阻力最小路径。
- scripts/new-seam.sh <PascalName> [lib子目录]
- 验证:生成样例 SampleProbe → flutter analyze 无 issue + test 过 → 清理
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-25 12:17:58 +08:00
wangjia
c5223af4a1
test(ci): L3 golden 权威环境脚本(进 CI 前置准备)
...
golden 真进 CI 卡两个硬约束:Linux/mac 渲染不一致(mac 基线在 CI 全红)+ 基线绑定
stats-overhaul dirty 工作区。本提交备好权威环境,不裹挟 dirty、不破坏:
- scripts/update-goldens.sh:在 CI 同款镜像 cirruslabs/flutter 重生成 Linux 权威基线
(开发者改 UI 后用它刷新,而非裸 mac --update-goldens,保持与 CI 一致)
- docs/test-architecture.html:L3 现状更新 + 列明启 CI 硬闸的两个前置条件
- 真启闸需:有 docker 的机器生成并提交 Linux 基线 + dirty 工作区合并(本机无 docker)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-25 12:16:16 +08:00
wangjia
fd82d82fe3
test(e2e): 第5刀b L4 gRPC 全链路(enroll→ReportUsage→统计真入库真读出)
...
在 HTTP 段基础上接 gRPC mTLS 全链路,真验证「统计准不准」:
- 脚本:生成 Node CA + gRPC server 证书(镜像 deploy.sh)、起 server 带 gRPC、
nodectl 签 bootstrap token,传 E2E_GRPC_ADDR/CA/token/node 给 driver
- driver:复用 agentd.EnsureEnrolled 真 TCP enroll → enroll 到的 client cert
建 mTLS → ReportUsage 注入 1GiB/100MiB(dp_uuid=用户) → 轮询 /v1/usage
断言 bytes_up=1GiB·bytes_down=100MiB 真入库真读回
- 本地全链路绿;go build ./... 不受影响(tag e2e)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-25 07:04:26 +08:00
wangjia
b3cbeef7cf
test(e2e): 第5刀a L4 进程级冒烟编排 + HTTP 段
...
真起 server 二进制(sqlite + Redis)跑 HTTP 用户旅程,验证 in-process 测试给不了的
信心(二进制起/迁移/路由/鉴权/DB 端到端):
- scripts/e2e-smoke.sh:起栈编排(Redis 三选一:已有 addr / docker / 内嵌 miniredis
兜底)+ 随机端口 + trap 清理;调 Go driver
- server/test/e2e/smoke_test.go (tag e2e):造用户(复用 argon2 HashPassword)
→ 登录 → /v1/me(dp_uuid/plan/email) → /v1/usage 鉴权 + 无 token 401
- server/test/e2e/miniredis (tag e2e):无 docker 时 Redis 兜底 launcher
- 本地绿;go build/test ./...(无 tag)仍 25 包绿,tag e2e 文件被静默跳过
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-25 06:59:39 +08:00
wangjia
306d8e5247
Merge branch 'main' into worktree-monitor-debounce
...
# Conflicts:
# scripts/vpn_test.py
2026-06-22 15:08:11 +08:00
wangjia
7a4d0cf7cd
fix(diag): host 参数走 base64 避免 GFW 拦明文敏感词诊断请求
...
控制面跑明文 HTTP 在国外 IP 上,白盒诊断请求 URL 里出现 google/youtube 等 GFW
敏感词时被墙重置(返回空)→ 出海段拿不到、报告显示「—」。改:host 用 base64url
传(host_b64),响应也回 b64、不回明文,明文里无敏感词(不影响真实加密隧道流量)。
- diag.go: EgressTiming 支持 ?host_b64=,解码后查白名单,响应 echo b64
- vpn_whitebox.py: node_egress 用 base64url 编码 host
验证:cara(墙内)google/youtube 出海段从 None → 8-9ms,与 github/cloudflare 一致。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-22 14:34:05 +08:00
wangjia
a19406d041
feat(test): VPN 黑盒/白盒测试工具 + 索引页 + 链路时序图与阶段拆解
...
- vpn_test.py(黑盒):站点矩阵连通/延迟(TLS 握手口径)/吞吐,落 tests/vpn/runs/
并重建 index.html 索引(内嵌 meta、file:// 直开);索引含 cara→LA→Google 时序图
+ 步骤表
- vpn_whitebox.py(白盒):双 IP-echo 判国内是否被隧道 + 五段拆解;经控制面
/v1/diag/egress 取出海段,自动算「接入段=整轮−出海段」,报告出「阶段拆解」表
(对应时序图 橙=接入 / 绿=出海)
- tests/vpn/: runs 与生成的 index.html 为本地工件(.gitignore),README 说明用法
- docs/: vpn-testing-research.md(调研)+ vpn-test-plan.md(黑盒/白盒方案)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-22 14:12:46 +08:00
wangjia
98ba2b411e
test: VPN 黑盒测试工具改用 Python(零依赖)+ HTML 报告 + 国内外站点矩阵
...
- scripts/vpn_test.py:替换 vpn_test.sh。纯标准库(socket/ssl/urllib),覆盖国内外
常见站点矩阵(google/youtube/github/x/fb/ig/wiki/cloudflare/openai/reddit;
百度/腾讯/淘宝/京东/B站/微博/网易/知乎/阿里云),测连通+延迟+TTFB+DNS+出口IP+吞吐,
本机连通性(tun/系统扩展),生成自包含 HTML 报告(-o)。
- 延迟标准 = TLS 握手耗时(ssl 握手,纯链路往返),报告里标注 "TTL=按 TLS 计算、非 IP TTL";
TTFB 作参考。禁用 ping/tcp_connect(经 TUN 本地应答失真)。
- 删除 scripts/vpn_test.sh;文档引用同步更新为 .py。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JEHzjEcFzvGwgbxT6Wbt6c
2026-06-22 09:43:46 +08:00
wangjia
8fcc4e8b75
docs+test: VPN 测试方案(黑盒+白盒)+ 修正延迟测量方法
...
- docs/vpn-test-plan.md:黑盒+白盒两方向测试方案。白盒细化:链路五段拆解、
协议/出站选择(Clash API)、接入段 vs 出海段分段 RTT、连接/流量、稳定性
(长跑/Kill switch/GFW 三元组封锁与被动探测/热重载)。含初轮报告:cara 黑盒
15 PASS;吞吐 国内直连 74Mbps vs 国外经隧道 ~10-17Mbps(瓶颈在出海段)。
- scripts/vpn_test.sh:修正延迟测量——经 TUN 代理时 ping/tcp_connect 被隧道本地
应答(2-4ms 假象),改用 TLS 握手(time_appconnect)/ TTFB 作为真实 RTT。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JEHzjEcFzvGwgbxT6Wbt6c
2026-06-22 09:17:00 +08:00
wangjia
2d2baf887c
docs+test: macOS 隧道踩坑复盘/规则 + VPN 测试调研 + 黑盒测试工具
...
- docs/macos-sysext-realize-troubleshooting.html:补"运行时"章节(libbox 空指针、
接口时序、队列死锁、DNS 劫持)+ 运行时 checklist。
- docs/vpn-testing-research.md:VPN 测试调研(行业方法论 + GFW 专项 + Pangolin
分层测试项 + 三层测试工具设计)。
- CLAUDE.md:新增「client/ macOS 原生隧道」铁律章节(构建发版/系统扩展 realize 要求/
libbox+NE 集成/配置由服务端渲染/已知坑)。
- scripts/vpn_test.sh:客户端侧黑盒测试工具(出口 IP/DNS/可达性/延迟/吞吐/IPv6 泄漏,
PASS/WARN/FAIL,可远程跑)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JEHzjEcFzvGwgbxT6Wbt6c
2026-06-22 09:00:10 +08:00
wangjia
447f3f494e
feat(client/macos): P1 原生隧道——PacketTunnel 系统扩展可加载 + libbox 运行
...
经长链路排查(同机对照可工作的 Tailscale),修复 macOS 系统扩展 realize
失败(OSSystemExtensionErrorDomain code=4)与 libbox 运行时崩溃,使内嵌
sing-box 的系统扩展能在 macOS 15 上激活并启动隧道。
系统扩展 realize(三个叠加根因):
- 扩展自包含:PacketTunnel 加 OTHER_LDFLAGS="" 切断对项目级 CocoaPods 链接
标志的继承(原会把 flutter_secure_storage 链进扩展);Libbox.xcframework
改纯 Link(静态),从 Embed Frameworks 移除冗余内嵌
- bundle 名 = 标识符:PRODUCT_NAME 设为 com.pangolin.pangolin.PacketTunnel
- 扩展 Info.plist 补 NSSystemExtensionUsageDescription(网络扩展类别强制要求)
- App Group 改 macOS 原生格式 BYL4KQHMTN.com.pangolin.pangolin;NEMachServiceName
以其为前缀;扩展补 network.client/server;get-task-allow=false + 签名加 --timestamp
- CFBundleVersion 随构建递增(否则 sysextd 视为同版本不更新)
libbox 运行时:
- startOrReloadService(options:) 传 nil 致空指针 SIGSEGV → 传 LibboxOverrideOptions()
- 默认接口监控阻塞到首个 path 更新再返回,修 "no available network interface"
配套:
- scripts/local_test.sh:build/sign/notarize/copy/run 一条龙(Developer ID + 公证)
- client/macos/sign_libbox.sh:构建期以 Developer ID 重签内嵌 Libbox
- VpnChannel:401 自动刷新 token、详尽 os_log;auth/api 统一走 kApiBaseUrl
- docs/macos-sysext-realize-troubleshooting.html:完整踩坑复盘
WIP / 临时(后续清理):
- 隧道运行时仍在排查:剥离远程 rule-set 后 sing-box 启动卡点未定位
- 含临时诊断代码:main.swift stderr 重定向、box.log 输出、rule-set 剥离、debug 日志
- api_config 仍指向联调节点,发版前还原
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JEHzjEcFzvGwgbxT6Wbt6c
2026-06-21 21:18:33 +08:00
wangjia
236e33aef9
feat(scripts): P0 完成 — libbox 嵌入式核心构建脚本(方案B)
...
scripts/build-libbox.sh:用 sagernet/gomobile fork v0.1.12 + sing-box v1.13.13
+ 官方 build_libbox,一键编出 Libbox.xcframework(Apple)/ Libbox.aar(Android)。
已本地跑通 macOS:双架构(arm64+x86_64)xcframework,Headers 暴露 LibboxNewService /
LibboxCommandClient(状态·速率)等 API。产物不入 git(~204MB),按需重编。
docs/vpn-core-embedding.md 标记 P0 完成。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 10:07:02 +08:00
wangjia
51a5170b9e
feat(scripts): 新增 speedtest.sh 隧道测速/质量验证工具
...
连上 pangolin 后一键测:出口IP确认 / 客户端→节点真实路径(绑en0绕隧道,
RTT+丢包) / 经隧道TTFB / Cloudflare 下行+上行带宽;--node 可 ssh 节点测
其自身出口带宽做理论上限对照。零依赖(curl+ping)。
实测节点(RackNerd 512MB/1核,LA):下行~22-24 / 上行~25 Mbps,RTT 298ms,
0% 丢包(晚高峰偶发瞬时丢包)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-18 22:48:44 +08:00
wangjia
bdf67cb56e
fix(client-config): 加 route.default_domain_resolver(sing-box 1.12+ 必需)
...
sing-box 1.13 对缺失 default_domain_resolver 直接 FATAL。加 {"server":"local"}
后,节点下发的整份客户端配置经 `sing-box check` 验证通过(无 FATAL/废弃)。
顺带 local_test.sh:免密已生效则跳过(不再反复要密码)+ --no-build 快速重跑。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-18 21:35:50 +08:00
wangjia
25c7bd75aa
feat(client+scripts): release 本地真测 — local_test.sh + 内核查找加 /opt/homebrew
...
ci-pangolin / Lint — shellcheck (push) Has been cancelled
ci-pangolin / OpenAPI Sync Check (push) Has been cancelled
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Has been cancelled
ci-pangolin / Flutter — analyze + test (push) Has been cancelled
- scripts/local_test.sh:一键构建 release macOS 包 + 配 sing-box 免密 sudoers
(TUN 需 root)+ 前台运行真身(日志直出),让本地测试 = release 线上行为
- kernel_process 二进制查找兜底加 /opt/homebrew/bin/sing-box(Apple Silicon
brew),release 包从 Finder/直接启动也能找到内核,免设 PANGOLIN_SINGBOX_BIN
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-18 21:09:08 +08:00