#30 · 2026-07-05 · 设计定稿待审 · 范围 A~F(排除 iOS、备份#26、TLS#25)· 真相源 docs/superpowers/specs/2026-07-05-cicd-design.md
.gitea/workflows + scripts/ci/*.sh 结构,适配 pangolin 的部署目标(pangolin1 /
pangolin.yanmeiai.com)与多端产物。现状:仅 ci.yml 校验无部署,服务端手动部署、官网未部署、下载死链。
| 子块 | 内容 |
|---|---|
| A 基座 | scripts/ci/*(env/provision/test/release/notify/lib-forgejo)+ checks 保留 |
| B 官网 | Astro 构建 → 部署 pangolin.yanmeiai.com |
| C 服务端 | 交叉编译 server/agent/migrate → release → ssh pangolin1(备份→migrate→换二进制→重启→健康检查) |
| D Android | apk(arm64,release keystore 签名)→ release 资产 |
| E macOS | 公证 dmg(Developer ID + notarytool)→ release 资产 |
| F Windows | exe/installer(Inno Setup)→ release 资产 |
排除:iOS(G,未来)、SQLite 备份/容灾(#26)、控制面 TLS(#25)。
| 维度 | 决定 | 理由 |
|---|---|---|
| runner | nas=官网+服务端(容器化)· mac=Android+macOS · windows=Windows | nas 常在线且 Astro/Go 轻量(非 Flutter Web);mac/windows 做必须它们的活 |
| 触发 | tag site-v* / server-v* / client-v* + manual.yml 手动派发 | 同 jiu,发版即部署,可手动重放 |
| macOS 签名 | mac 自动 Developer ID 签名 + notarytool 公证 + staple | 凭据入 secret(见 §6) |
| Android 签名 | 正式 release keystore | app 级专属签名身份 |
| 下载链接 | 官网 href 指向 Gitea release 稳定资产 URL | 发版即更新,见 §5 |
| 镜像 | goproxy.cn / flutter-io.cn | 国内网络 |
scripts/ci/(镜像 jiu)_env.sh —— 公共环境(镜像源、路径、版本号解析 ${tag#prefix-v})lib-forgejo.sh —— release 建/查 + 资产上传(用 FORGEJO_TOKEN)provision-mac.sh —— mac 幂等装 flutter / xcode-select / gomobile / NDK+JDK17test.sh、notify.sh、compile-*.sh、deploy-*.sh、release-*.sh每个 compile-* 封装该端已验证的构建命令(Android 走 build-libbox.sh android +
flutter build apk --split-per-abi;macOS 走 Developer ID 签名 + notarytool submit --wait +
stapler)。工作流只调脚本,逻辑在脚本里、便于本地复现。
.gitea/workflows/| 工作流 | 触发 | runner | 步骤 |
|---|---|---|---|
checks.yml(现 ci.yml) | push 分支 | nas | 保留:shellcheck / openapi / redline / flutter analyze+test / go test |
deploy-site.yml | site-v* | nas | node:20 构建 Astro(注入 SITE_URL)→ deploy-site.sh |
deploy-server.yml | server-v* | nas | golang:1.25 交叉编译 → test → release → deploy-server.sh |
build-android.yml | client-v* | mac | provision → compile-android.sh(签名 apk)→ release |
build-macos.yml | client-v* | mac | provision → compile-macos.sh(签名+公证 dmg)→ release |
build-windows.yml | client-v* | windows | compile-windows.sh(exe/installer)→ release |
pangolin-{server,agent,migrate} 到 pangolin1 /tmpsystemctl stop pangolin-serverwal_checkpoint(TRUNCATE) → cp 备份 pangolin.db.bak-pre-<tag>pangolin-migrate up(pangolin 用户);失败即恢复备份 + 重启旧 server + 退出非零install 新二进制到 /usr/local/bin(旧的备份为 .bak-<tag>)systemctl start + /healthz 健康检查;agent 随连接自恢复:443 被 sing-box(VPN 数据面)占用,而 CF 免费套餐 proxied 回源只能打 :80/:443、改回源端口需 Enterprise —— 同机同 IP 上官网 HTTPS 与 VPN 无法共存。故官网改由 Cloudflare Pages 托管:纯静态、全程 HTTPS、_headers/CSP 原生生效、不落 VPS,从根上无 :443 冲突,也不拖累 VPN 机器。已上线 https://pangolin.yanmeiai.com。
Astro npm ci && npm run build(SITE_URL=https://pangolin.yanmeiai.com)→ dist/
经 npx wrangler pages deploy 发布到 Pages 项目 pangolin-site(自定义域 pangolin.yanmeiai.com,CNAME → pangolin-site.pages.dev,proxied)。需 secret CLOUDFLARE_API_TOKEN(带 Account>Pages>Edit)+ CLOUDFLARE_ACCOUNT_ID;deploy 步骤在 node:20 容器内跑 wrangler。灾备:产物仍纯静态,可另 rsync 到镜像。
web/website/src/config/site.ts 增 downloads:{ android, macos, windows },值为 Gitea release
稳定 latest 资产 URL(Forgejo 支持 …/releases/latest/download/<asset> 则直用;否则构建期用
FORGEJO_TOKEN 查最新 client-v* 版本烘焙进 href)。Download.astro 各平台按钮读
SITE.downloads.<platform>。客户端发版后官网重部署即刷新(或 build-* 完成触发 deploy-site)。
| Secret | 作用域 | 说明 |
|---|---|---|
FORGEJO_TOKEN / FORGEJO_URL | 账户级 | 建 release + 传产物,jiu 复用 |
MACOS_DEVELOPER_ID_CERT_P12_BASE64 / MACOS_DEVELOPER_ID_CERT_PASSWORD | 账户级 | Developer ID 证书(账号级),与 jiu 共用;续期改一处 |
APPSTORE_API_KEY_P8_BASE64 / APPSTORE_API_KEY_ID / APPSTORE_API_ISSUER_ID | 账户级 | 公证 API key(KEY_ID=3PZTHR8YMJ),与 jiu 同一把 |
DEPLOY_SSH_KEY | pangolin 仓库级 | 授权到 pangolin1,最小权限 |
ANDROID_KEYSTORE_BASE64 / ANDROID_KEYSTORE_PASSWORD / ANDROID_KEY_ALIAS / ANDROID_KEY_PASSWORD | pangolin 仓库级 | Android app 级专属签名(pangolin 自己的 keystore,不复用 jiu) |
MACOS_APP_PROVISION_PROFILE_BASE64 / MACOS_SYSEXT_PROVISION_PROFILE_BASE64 | pangolin 仓库级 | 主 app + PacketTunnel sysext 描述文件(pangolin bundle 专属) |
命名对齐 jiu(MACOS_*/APPSTORE_*/ANDROID_*):Apple 那套放账户级 → jiu/pangolin 共用一份,compile-macos 脚本可复用 jiu 的;Android keystore 虽同命名规范但各 app 独立、不共享。工作流用 secrets.XXX 引用,作用域对写法透明。
范围虽 A~F,按风险/依赖递增落地,每阶段独立可发、独立验收:
checks 迁移(抽 scripts/ci 骨架)workflow_dispatch 手动跑通、核对产物/部署,再依赖 tag。server-v* → migrate 版本 + /healthz + 行数守恒(同 F3 核对)。site-v* → 站点可访问 + canonical 正确 + redline 扫描。spctl / Windows 安装)。| 风险 | 缓解 |
|---|---|
| nas 内存(3.8G)构建 OOM | 容器化单 job、Astro/Go 轻量;必要时该端移 mac |
| migrate 在生产出错 | 部署前备份 + 失败自动回滚(§3.3),已在 F3/F4 手动验证 |
| Android keystore 丢失 | 存 Bitwarden(文件+密码);终身签名身份 |
| macOS 公证凭据泄露 | 账户级 secret,不落盘;.p8/.p12 用完即删临时文件 |
| 发版后下载链接不刷新 | build-* 成功触发 deploy-site 重烘焙,或用 latest-download 稳定 URL |
iOS 流水线(G)、SQLite 备份/容灾(#26)、TLS(#25)、上架 Play、Windows 代码签名(先不签)。