Files
ai-proj-helper/skills-dev/slark-cicd-plugin/skills/SKILL.md
T
2026-08-26 06:33:14 +09:30

16 KiB
Raw Blame History

name, description
name description
slark-cicd Slark 仓库 staging、生产和 Desktop 安装包的端到端 CI/CD 可执行 runbook。覆盖本地预推快检、PR 与内网 ci/internal-gate 门禁、合并 origin/main、生产前强制 staging 验收、审批式生产发布,以及在 m5max 构建签名、公证并上传 macOS/Windows Desktop 包到 OSS。当用户要在 slarkqiudl/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 位 SHAHEAD != origin/main 会被 deploy.sh 拒绝。
  • 生产发布必须在普通 clone 中执行,且 .git 必须是目录;release-prod.sh / deploy.sh 会拒绝 .git 为指针文件的 git worktree。不要污染现有 checkout:主目录脏或被占用时,新建干净的临时 clone。
  • 生产发布前必须先发布并验收 staging,不得跳过:同一最新 origin/main 精确 SHA 必须先完成迁移演练、 staging 正式部署、隔离检查和需求功能验收。把证据报告给用户后,必须再次取得明确的生产确认;开始 staging 前获得的生产授权不能替代这次确认。未通过、未完成或用户未确认时停止,不得执行生产发布命令。
  • 审批式部署,永不自动:亲手敲的 sudo/rm -rf/dd/curl|sh/包安装是 destructiveNEVER_AUTO), 每次都要人审;命中审批闸就等人批,绝不绕过、绝不把这些 key 加进 auto-approve 白名单。
  • staging 与生产硬隔离:staging 脚本带生产 IP 拒运行护栏、不 push origin、不反向 rsync。
  • 当前 Slark staging 权威目标是 AWS ap-southeast-2 实例 i-013e5ca3fdfddc13e Name=slark-staging2026-08-18 核验公网 IP 15.135.112.181)。公网 IP 自动分配,发布前必须按 实例 ID 重查并确认 Name/状态;不得凭历史 IP 判断目标。
  • 82.157.141.202 是 ai-proj 预生产宿主机。其 /opt/slark-staging cohost 是隔离的 Slark 兼容验收栈, 但不是 Slark 独立预生产;只有任务明确指定 cohost 时才能使用,不得作为普通 Slark staging 的默认目标。
  • staging 发布若影响 packages/daemonpackages/runtime、Server/daemon 公共协议或 Desktop 公共运行链, 必须把 server-stagingdaemon-staging 更新到同一精确 SHA;两者版本不一致不得宣告 staging 成功。
  • 只修 PR 范围内的 CI 失败;不为过检去改 CI/workflow 或做无关改动。

选择链路

  • 「发布/上线/部署生产」→ 生产发布链:阶段 1→2→3(同 SHA staging 验收)→ 人工确认 →4→5。
  • 「Desktop/桌面版打包、发布、上传 OSS」→ 阶段 1→2 后走 docs/desktop-oss-release.md 的 m5max 双平台链路。
  • 「盯 CI/合并 PR」→ 阶段 1→2(用 babysit 心态循环到 green + mergeable + 评论收口)。
  • 「复现/验证运行时行为、别碰生产」→ staging 预验链(阶段 3,可独立随时跑)。

阶段 1PR 与内网 gateci/internal-gate

真实门禁是内网 CIGitHub 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=MERGEABLEmergeStateStatus=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 真机预验(生产前强制,也可独立运行)

生产候选必须使用最新 origin/main 的同一精确 SHA。先执行迁移演练,再正式部署;随后完成隔离检查和本次需求的 功能验收。验收不能只看通用 health:凡需求涉及真实集成(如飞书 OAuth),staging 缺少对应 provider/凭据时必须 明确标为未完成并停止生产链,除非用户在看到该限制后明确接受。完成后报告目标实例、SHA、Server/Daemon revision、 迁移演练、健康、隔离和功能结果,并等待用户再次确认是否进入生产。

3.1 当前权威路径:Slark 独立 staging

稳定目标是 AWS ap-southeast-2 实例 i-013e5ca3fdfddc13eName=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:生产发布(审批式)

前置门禁:阶段 3 已对同一 SHA 完成 staging 部署和验收,证据已报告,且用户在报告之后明确确认生产发布。 缺任一项即停止;不得把 PR 合并授权、较早的生产授权或单纯的“继续”视为验收后确认。

唯一姿势:从干净的普通 clone 发布最新 origin/mainHEAD == 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.shcheck-production-release-sha.shHEAD == origin/main SHA,不符即拒。
  • --backend 才跑迁移:owner 连接(DDL 权)与运行时 slark_app(DML-only)分离;幂等、失败即非零。
  • 命中审批闸(发布/sudo)→ 等人批;不要绕。脚本内部 SSH 载荷子进程的 sudo 不触发闸。
  • 普通工作 clone 发布完切回原分支:git checkout <branch>;一次性发布 clone 可保留作审计,清理时用可恢复方式。

HANDOFF_BLOCKED 恢复入口

发布准备遇到 HANDOFF_BLOCKED、handoff manifest=failed_closed 或命令状态不确定时,停止发布切换;禁止靠重跑 发布脚本、直接改表或默认 replay 来“解卡”。先把 manifest、命令、execution、lease/outbox 和审计证据做只读盘点, 再让用户明确授权每条记录的 reconciliation action/outcome 及是否允许继续发布。恢复细节见 references/production-handoff-recovery.md;仅遇到该类事故时读取。

COMMAND_AUTHORITY_CHANGED 是有效并发护栏,不是可忽略错误:重新读取当前 authority/transport/execution generation 确认期间没有新活动,再在原授权范围内幂等续办。若发现新工作、活跃 lease/outbox 或无法解释的副作用,立即停止并 重新请求决策。

阶段 5:发布后核查

scripts/verify-deploy.sh    # 健康(前端/api/health=200)、bundle、server/daemon SHA、迁移集、federation、凭据

预期 ✓ deploy verification passed: server=<sha> daemon=<sha><sha> == origin/main,舰队 online ≥ 发布前。 完成前还要独立复核 governed release 账本为 succeeded/complete、四组件实际 SHA 均为目标 SHA、租约已释放、 新 handoff manifest=verified;若本次处理过旧 manifest,还要核对其全部 case 已达授权终态且 replay 数为 0。

默认生产包装器使用 --no-mirror:构建 daemon candidate binary 用于运行态验证不等于上传镜像资产。镜像落后告警 在该模式下是预期的非阻断结果;不得未经单独授权补传镜像。交付说明要明确国内安装器可能回退 upstream,避免把 本地构建、生产 daemon 更新和镜像上传混为一谈。

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 不符 部署到了旧码,重发
HANDOFF_BLOCKED / manifest=failed_closed 停止切换并读取 handoff recovery 参考;只读盘点后取得逐项 action/outcome 授权,禁止默认 replay
reconciliation 返回 COMMAND_AUTHORITY_CHANGED 查当前 generation 与新活动;无新活动才在原授权内幂等续办,有变化则停止重新决策
--no-mirror 后提示镜像落后 预期非阻断;报告 upstream fallback,未经单独授权不上传镜像
生产授权已给但 staging 尚未验收 先完成同 SHA staging 全量验收,报告证据并重新等用户确认;不得沿用较早授权
staging 缺少需求依赖的真实集成配置 将对应验收标为未完成并停止生产链;补齐配置后重验,或让用户基于明确限制作决定

ai-proj 流程(强制)

任何改产品/代码行为的工作,动手前先在 ai-proj 立项 + 建 Task + 关联,实现/测试/交付回写; commit/PR 引用 REQ-...。纯文档/工具/只读排查除外。详见仓库 AGENTS.md / CLAUDE.md