13 KiB
name, description
| name | description |
|---|---|
| slark-cicd | Slark 仓库 staging、生产和 Desktop 安装包的端到端 CI/CD 可执行 runbook。覆盖本地预推快检、PR 与内网 ci/internal-gate 门禁、合并 origin/main、staging 真机预验、审批式生产发布,以及在 m5max 构建签名、公证并上传 macOS/Windows Desktop 包到 OSS。当用户要在 slark(qiudl/qiu-slark)里发布/上线、部署到生产或 staging、发布 Desktop 安装包、盯 CI/合并 PR、复现或验证运行时行为、或排查发布链/推送路由问题时使用。 |
Slark CI/CD runbook
驱动 Slark 从改代码到上线的端到端流程。权威流程与完整细节见仓库文档
docs/cicd-staging-production.md(本技能命令与之一致);本文件是可直接照做的分阶段清单。
仓库:qiudl/qiu-slark(本机克隆通常在 /Users/donglinlai/coding/slark)。所有命令在仓库根执行。
ai-proj 相关命令加 GODEBUG=netdns=go 前缀。
铁律(先记死)
- GitHub
origin/main是唯一代码权威、合并入口与生产发布来源;internal只用于 CI/镜像,永不发布。 - 生产发布只接受最新
origin/main的精确 40 位 SHA;HEAD != origin/main会被deploy.sh拒绝。 - 生产发布必须在普通 clone 中执行,且
.git必须是目录;release-prod.sh/deploy.sh会拒绝.git为指针文件的 git worktree。不要污染现有 checkout:主目录脏或被占用时,新建干净的临时 clone。 - 审批式部署,永不自动:亲手敲的
sudo/rm -rf/dd/curl|sh/包安装是destructive(NEVER_AUTO), 每次都要人审;命中审批闸就等人批,绝不绕过、绝不把这些 key 加进 auto-approve 白名单。 - staging 与生产硬隔离:staging 脚本带生产 IP 拒运行护栏、不 push origin、不反向 rsync。
- 当前 Slark staging 权威目标是 AWS
ap-southeast-2实例i-013e5ca3fdfddc13e(Name=slark-staging,2026-08-18 核验公网 IP15.135.112.181)。公网 IP 自动分配,发布前必须按 实例 ID 重查并确认 Name/状态;不得凭历史 IP 判断目标。 82.157.141.202是 ai-proj 预生产宿主机。其/opt/slark-stagingcohost 是隔离的 Slark 兼容验收栈, 但不是 Slark 独立预生产;只有任务明确指定 cohost 时才能使用,不得作为普通 Slark staging 的默认目标。- staging 发布若影响
packages/daemon、packages/runtime、Server/daemon 公共协议或 Desktop 公共运行链, 必须把server-staging与daemon-staging更新到同一精确 SHA;两者版本不一致不得宣告 staging 成功。 - 只修 PR 范围内的 CI 失败;不为过检去改 CI/workflow 或做无关改动。
选择链路
- 「发布/上线/部署生产」→ 生产发布链:阶段 1→2→4→5。
- 「Desktop/桌面版打包、发布、上传 OSS」→ 阶段 1→2 后走
docs/desktop-oss-release.md的 m5max 双平台链路。 - 「盯 CI/合并 PR」→ 阶段 1→2(用 babysit 心态循环到 green + mergeable + 评论收口)。
- 「复现/验证运行时行为、别碰生产」→ staging 预验链(阶段 3,可独立随时跑)。
阶段 1:PR 与内网 gate(ci/internal-gate)
真实门禁是内网 CI(GitHub Actions 已停用)。检查与自查:
gh pr checks <PR> # 应见 ci/internal-gate
gh pr view <PR> --json state,mergeable,mergeStateStatus,isDraft,reviewDecision
- 基础门(全 PR):release-contract / member-gate / authz-matrix / controlled-content-exits / onconflict-predicate / migration-idempotency / wsl-path-translation / typecheck / test(全量)。
- 条件外部门(按改动路径):改 server DB/迁移/schema →
postgresql-security;改 web →web-e2e; android / daemon+desktop 各有门。 - 本地复跑基础门可跑部分:
pnpm -r typecheck && pnpm test。
红了:只修本 PR 范围内的失败。疑似无关的合并阻塞→先 merge 最新 main(可能别的 PR 已修)。
BLOCKED: <label> requires <VAR> = runner 环境未配外部门命令,属运维问题,不是 PR 代码问题。
阶段 2:合并到 origin/main
合并前确认:mergeable=MERGEABLE、mergeStateStatus=CLEAN、非 draft、ci/internal-gate 绿、评论收口。
gh pr merge <PR> --merge # 仓库风格:merge commit
若本机 main 被其他 worktree 占用导致 --delete-branch 本地 checkout 失败(属本地副作用):
gh pr view <PR> --json state,mergedAt,mergeCommit # 确认 GitHub 侧 MERGED
git push origin --delete <feature-branch> # 删远端
git branch -D <feature-branch> # 删本地(先切走)
阶段 3:staging 真机预验(可选,随时)
3.1 当前权威路径:Slark 独立 staging
稳定目标是 AWS ap-southeast-2 实例 i-013e5ca3fdfddc13e(Name=slark-staging)。它使用自动分配
公网 IP,因此每次部署前先查询当前 IP;2026-08-18 核验值为 15.135.112.181:
aws ec2 describe-instances --region ap-southeast-2 \
--instance-ids i-013e5ca3fdfddc13e \
--query 'Reservations[0].Instances[0].{Name:Tags[?Key==`Name`]|[0].Value,State:State.Name,PublicIp:PublicIpAddress}' \
--output table
export STAGING_SSH_KEY=~/.ssh/cloud-server-syd.pem
export STAGING_REMOTE=ubuntu@15.135.112.181
export STAGING_REMOTE_IP=15.135.112.181
export STAGING_BASE=http://15.135.112.181
scripts/deploy-staging.sh --migrate-dry-run
scripts/deploy-staging.sh
STAGING_TOKEN=$(cat /tmp/.staging_token) scripts/staging-seed.sh
scripts/staging-verify-isolation.sh
不得把查询到的 Name 非 slark-staging 的机器当作目标。四件套细节与环境隔离约束见
docs/req-20260811-0059-staging-environment-design.md。
3.2 非权威路径:ai-proj cohost(仅明确指定时)
ai-proj cohost 位于 ubuntu@82.157.141.202:/opt/slark-staging。全程使用隔离数据、数据库、密钥和状态目录,
但宿主机身份仍是 ai-proj staging;普通“Slark 预生产”不得走这里。仅在任务明确要求 cohost 兼容验收时,
先在干净的独立 worktree检出待验精确 SHA,再执行:
STAGING_SSH_KEY=~/.ssh/ai_proj_stg.pem \
STAGING_KNOWN_HOSTS_FILE=~/.ssh/known_hosts \
STAGING_REMOTE=ubuntu@82.157.141.202 \
STAGING_REMOTE_IP=82.157.141.202 \
scripts/deploy-staging-cohost.sh
如果改动影响 daemon/runtime/公共协议,还需用 Compose daemon profile 更新 daemon-staging,并核对
Server/daemon revision 同为待验 SHA。
3.3 环境选择检查
普通 Slark staging 默认走 3.1;只有用户或需求明确说“ai-proj cohost”才走 3.2。任何验收都必须记录: 环境稳定身份、当次 IP、待验 40 位 SHA、Server/daemon revision/status、Server health 和目标功能结果。
routed-remote 要 network=enabled 必须同时满足:① agent workspace_access=write +
repository_access=write;② per-agent 工作区是可写 git worktree。细节见
docs/req-20260811-0059-staging-environment-design.md。staging 刻意不碰 deploy.sh 的生产闸门。
阶段 4:生产发布(审批式)
唯一姿势:从干净的普通 clone 发布最新 origin/main(HEAD == origin/main 精确 SHA)。staging 可用
独立 worktree,但生产脚本为保证同步与发布边界,会拒绝 worktree;不要在用户已有脏 checkout 中清理或发布。
# 若当前仓库不是普通 clone,先在安全父目录创建一次性干净 clone:
git clone https://github.com/qiudl/qiu-slark.git <clean-production-clone>
cd <clean-production-clone>
git fetch origin main
test -d .git # 必须通过;worktree 的 .git 是文件
git status --porcelain # 必须干净
git checkout --detach "$(git rev-parse origin/main)" # 在产品分支上时先 detach 到该 SHA
pnpm release:prod # = release-prod.sh → deploy.sh --backend --no-install --no-mirror
# 备选:scripts/deploy.sh --pull --backend
deploy.sh用check-production-release-sha.sh锁HEAD == origin/mainSHA,不符即拒。--backend才跑迁移:owner 连接(DDL 权)与运行时slark_app(DML-only)分离;幂等、失败即非零。- 命中审批闸(发布/sudo)→ 等人批;不要绕。脚本内部 SSH 载荷子进程的 sudo 不触发闸。
- 普通工作 clone 发布完切回原分支:
git checkout <branch>;一次性发布 clone 可保留作审计,清理时用可恢复方式。
阶段 5:发布后核查
scripts/verify-deploy.sh # 健康(前端/api/health=200)、bundle、server/daemon SHA、迁移集、federation、凭据
预期 ✓ deploy verification passed: server=<sha> daemon=<sha> 且 <sha> == origin/main,舰队 online ≥ 发布前。
镜像落后告警(默认 --no-mirror)非阻断,需补推按告警的幂等命令(需 Bitwarden session);镜像仅单向 fast-forward。
Desktop m5max 双平台发布
Desktop 安装包不走 Server 生产部署脚本。权威流程见仓库 docs/desktop-oss-release.md,已验证基线为
REQ-20260819-0005 / Desktop 0.3.1:
- 版本 PR 通过
ci/internal-gate并合并后,m5max 从最新origin/main精确 SHA 的干净普通 clone 构建。 - m5max 原生构建、Developer ID 签名并公证/staple macOS DMG/ZIP;交叉构建 Windows x64 NSIS EXE。
- Darwin 不能执行 Windows 原生
smoke:windows。只有发布负责人明确接手 Windows 原生验收时才能继续交叉打包,交付证据必须标注该边界。 - 资产不回传开发机;由 m5max 直接上传
xiaoqu-public-file/slark/desktop/releases/v<version>/,manifest 最后更新。 xiaoqu-public-file的 canonical 凭证源是发布控制机上的/Users/donglinlai/coding/param.rxt(必须为0600);AK/SK 分别位于 XML 标签ossAccessKeyId/ossAccessKeySecret。不得改猜 Bitwarden、Keychain、通用credentials.env或 m5max 本地配置;只有该文件缺失、权限不符或标签解析为空时才停止并报告。- m5max 不持久化 OSS 凭证。发布控制机从
param.rxt提取 AK/SK 后,只用printf '%s\n%s\n' ... | ssh m5max ...经 SSH stdin 传两行;远端用read -r接收并仅为当次 shell 导出OSS_ACCESS_KEY_ID/OSS_ACCESS_KEY_SECRET,随后运行上传脚本。禁止scp凭证文件、写远端临时文件或把值打印到日志。 - m5max 非交互 SSH 必须显式补
PATH=/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin:$PATH;已验证ossutil位于/Users/johnq/.local/bin/ossutil。执行前检查 Node、三个安装包、精确 main SHA 和干净工作树,避免因交互 shell 环境差异重新猜路径。 - m5max 默认出口若走
utun,只为当次ossutil使用--bind-address "$(ipconfig getifaddr en0)",不得修改整机 Tailscale/默认路由。 - 完成前核对三份资产 SHA256/大小、macOS 签名与公证、公开 URL/manifest,并回写 ai-proj 证据。
推送路由自查(换机器/新克隆必做)
git remote -v # origin 收发都应是 https://github.com/qiudl/qiu-slark.git
git config --get-regexp '^url\.' # 有输出 = pushInsteadOf 改写,push 可能被静默重定向到内网
scripts/git-release-governance.sh check-local
scripts/git-release-governance.sh status
故障分流
| 现象 | 处置 |
|---|---|
release-prod 拒绝 HEAD≠origin/main |
git fetch origin main 后 detach 到 origin/main SHA,工作树须干净 |
release-prod 拒绝 git worktree / .git 不是目录 |
改用干净的普通 clone,锁定最新 origin/main;不要在现有脏 checkout 中强行切换 |
ci/internal-gate red |
看 gate 分组日志找 FAIL 项;pnpm -r typecheck && pnpm test 本地复现修复 |
BLOCKED: <label> requires <VAR> |
runner 未配外部门命令,报运维配 SLARK_CI_*_CMD,非 PR 问题 |
| 合并阻塞但与 PR 无关 | merge 最新 main 再看 |
| push 成功但 GitHub 没有 | 查 git config --get-regexp '^url\.',移除 pushInsteadOf 或显式指定 GitHub URL |
| staging routed-remote 恒断网 | 查两道放网杠杆(workspace_access=write + 可写 git worktree) |
| cohost Server 已更新但 daemon 仍是旧 SHA | 用 --profile daemon up -d daemon-staging 更新 daemon;核对两容器 revision 后才算完成 |
| cohost daemon 启动即退出/fatal | 看 docker logs slark_daemon_staging;修复凭据/环境或版本契约,禁止用旧 daemon 冒充验收通过 |
| verify 失败 SHA 不符 | 部署到了旧码,重发 |
ai-proj 流程(强制)
任何改产品/代码行为的工作,动手前先在 ai-proj 立项 + 建 Task + 关联,实现/测试/交付回写;
commit/PR 引用 REQ-...。纯文档/工具/只读排查除外。详见仓库 AGENTS.md / CLAUDE.md。