docs: 迁移 Runbook 更新——代码侧已完成(signing.env 单源 + codegen)
Team ID 已知(44WULXM6SV),§3 代码替换已落地并收敛为单一真相源:改写 §3 为 「signing.env + gen-signing.mjs codegen + drift 闸」,占位 <NEW_TEAM> 全替为真值, 顶部进度卡与 §6 责任表标注代码侧完成。剩余为 Apple 后台建资产/本机公证/gitea/验证。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
This commit is contained in:
@@ -66,23 +66,23 @@
|
||||
顺序很重要:<strong>先建 Apple 资产 → 我改代码 → 传 gitea → 验证首个构建</strong>。
|
||||
</div>
|
||||
|
||||
<div class="card warn">
|
||||
<h3>⚠️ 动手前唯一的阻塞项:新 Team ID</h3>
|
||||
<p>代码替换需要美国账号的 <strong>10 位 Team ID</strong>。登录 <a href="https://developer.apple.com/account">developer.apple.com/account</a> → 左栏 <b>Membership details</b> → <b>Team ID</b>(形如 <code>A1B2C3D4E5</code>)。把它发我,我就执行全量代码替换。本文中一律用 <code><NEW_TEAM></code> 占位。</p>
|
||||
<div class="card ok">
|
||||
<h3>✅ 进度:代码侧已完成(Team ID = <code>44WULXM6SV</code>)</h3>
|
||||
<p>仓库代码(§3)已全量迁到美国身份并收敛成单一真相源 <code>scripts/signing.env</code> + codegen。<strong>剩下的是你在 Apple 后台建资产(§1)、本机公证凭据(§2)、gitea 换 secret(§4)、首个构建验证(§5)。</strong>建资产时把两张证书精确全名 + ASC Key 的 Key/Issuer ID 发我,我做 §2。</p>
|
||||
</div>
|
||||
|
||||
<h2>0 · 命名总表(新账号下的目标身份)</h2>
|
||||
<table>
|
||||
<tr><th>项</th><th>旧(中国,待清除)</th><th>新(美国 Yanmei AI LLC)</th></tr>
|
||||
<tr><td>Team ID</td><td><code>BYL4KQHMTN</code></td><td><code><NEW_TEAM></code>(你提供)</td></tr>
|
||||
<tr><td>Team ID</td><td><code>BYL4KQHMTN</code></td><td><code>44WULXM6SV</code>(你提供)</td></tr>
|
||||
<tr><td>法人实体(证书 CN 内含)</td><td>Yanmei (beijing) Technology Co., Ltd</td><td>Yanmei AI LLC</td></tr>
|
||||
<tr><td>macOS 主 app Bundle ID</td><td><code>com.pangolin.pangolin</code></td><td><code>com.yanmeiai.pangolin</code></td></tr>
|
||||
<tr><td>macOS 扩展 Bundle ID</td><td><code>com.pangolin.pangolin.PacketTunnel</code></td><td><code>com.yanmeiai.pangolin.PacketTunnel</code></td></tr>
|
||||
<tr><td>iOS 主 app Bundle ID</td><td><code>com.pangolin.pangolinVpn</code></td><td><code>com.yanmeiai.pangolin</code></td></tr>
|
||||
<tr><td>iOS 扩展 Bundle ID</td><td><code>com.pangolin.pangolinVpn.PacketTunnel</code></td><td><code>com.yanmeiai.pangolin.PacketTunnel</code></td></tr>
|
||||
<tr><td>iOS App Group</td><td><code>group.com.pangolin.pangolinVpn</code></td><td><code>group.com.yanmeiai.pangolin</code></td></tr>
|
||||
<tr><td>macOS App Group(原生 <code><Team>.</code> 格式)</td><td><code>BYL4KQHMTN.com.pangolin.pangolin</code></td><td><code><NEW_TEAM>.com.yanmeiai.pangolin</code></td></tr>
|
||||
<tr><td>macOS <code>NEMachServiceName</code></td><td><code>BYL4KQHMTN.com.pangolin.pangolin.PacketTunnel</code></td><td><code><NEW_TEAM>.com.yanmeiai.pangolin.PacketTunnel</code></td></tr>
|
||||
<tr><td>macOS App Group(原生 <code><Team>.</code> 格式)</td><td><code>BYL4KQHMTN.com.pangolin.pangolin</code></td><td><code>44WULXM6SV.com.yanmeiai.pangolin</code></td></tr>
|
||||
<tr><td>macOS <code>NEMachServiceName</code></td><td><code>BYL4KQHMTN.com.pangolin.pangolin.PacketTunnel</code></td><td><code>44WULXM6SV.com.yanmeiai.pangolin.PacketTunnel</code></td></tr>
|
||||
</table>
|
||||
<p class="small">iOS App Group 不含 Team ID(<code>group.</code> 前缀,跨账号可移植);macOS 用原生 <code><TeamID>.<name></code> 格式,<strong>Team 一换前缀必变</strong>——这也是必须改代码而非纯换证书的根本原因。旧 macOS 安装的登录态存在旧 App Group 容器里,切换后清空、用户需重登(重签本就如此,可接受)。</p>
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
<h3>1.3 创建 App Group</h3>
|
||||
<p>Identifiers → 右上下拉切到 <b>App Groups</b> → + → 填 <code>group.com.yanmeiai.pangolin</code>(Description 随意)。回到上面 4 个 App ID,编辑其 <b>App Groups</b> capability → Configure → 勾上这个 group。</p>
|
||||
<div class="card"><p class="small"><b>macOS 端说明:</b>macOS 用的是原生 <code><NEW_TEAM>.com.yanmeiai.pangolin</code>(team 作用域容器,不带 <code>group.</code>),<strong>不需要在后台单独注册</strong>——只要 App ID 勾了 App Groups capability、且用该 Team 的证书签名即可生效。后台注册的 <code>group.com.yanmeiai.pangolin</code> 供 iOS 使用。</p></div>
|
||||
<div class="card"><p class="small"><b>macOS 端说明:</b>macOS 用的是原生 <code>44WULXM6SV.com.yanmeiai.pangolin</code>(team 作用域容器,不带 <code>group.</code>),<strong>不需要在后台单独注册</strong>——只要 App ID 勾了 App Groups capability、且用该 Team 的证书签名即可生效。后台注册的 <code>group.com.yanmeiai.pangolin</code> 供 iOS 使用。</p></div>
|
||||
|
||||
<h3>1.4 生成 2 张证书(Certificates)</h3>
|
||||
<p>用「钥匙串访问 → 证书助理 → 从证书颁发机构请求证书」生成一个 <code>CertificateSigningRequest.certSigningRequest</code>(存到磁盘),后台上传它换证书;下载后<strong>双击导入 login 钥匙串</strong>。</p>
|
||||
@@ -113,7 +113,7 @@
|
||||
<li><b>Developer ID Application</b>(macOS 站外分发 + 公证用)→ 下载 <code>developerID_application.cer</code>。</li>
|
||||
<li><b>Apple Distribution</b>(iOS ad-hoc / App Store / TestFlight)→ 下载 <code>distribution.cer</code>。</li>
|
||||
</ul>
|
||||
<p class="small">导入后,两张证书的主体会是 <code>Developer ID Application: Yanmei AI LLC (<NEW_TEAM>)</code> 与 <code>Apple Distribution: Yanmei AI LLC (<NEW_TEAM>)</code>。<strong>请把这两串完整名字发我</strong>(<code>security find-identity -v -p codesigning</code> 可打印),我要把它们精确写进 <code>local_test.sh</code>。</p>
|
||||
<p class="small">导入后,两张证书的主体会是 <code>Developer ID Application: Yanmei AI LLC (44WULXM6SV)</code> 与 <code>Apple Distribution: Yanmei AI LLC (44WULXM6SV)</code>。<strong>请把这两串完整名字发我</strong>(<code>security find-identity -v -p codesigning</code> 可打印),我要把它们精确写进 <code>local_test.sh</code>。</p>
|
||||
|
||||
<h3>1.5 导出 .p12(给 CI 用)</h3>
|
||||
<p>钥匙串里分别右键两张证书(连带私钥)→ 导出为 .p12,设一个导出密码(记进 Bitwarden,别写文件)。得到 <code>developerID.p12</code> 与 <code>ios_dist.p12</code>——第 4 节转 base64 传 gitea。</p>
|
||||
@@ -142,40 +142,28 @@
|
||||
<li>(可选)清理旧账号残留:删除 login 钥匙串里旧的 <code>… Yanmei (beijing) Technology</code> 两张证书,避免签名时误选旧身份。</li>
|
||||
</ol>
|
||||
|
||||
<h2>3 · 仓库代码全量替换 <span class="tag me">我做</span>(拿到 Team ID + 证书全名后)</h2>
|
||||
<p>下述文件里的旧 Team ID / Bundle ID / App Group / 实体名一次性替换。改完 <code>flutter build ios --no-codesign</code> + macOS 构建自检,确保工程仍自洽。</p>
|
||||
<h2>3 · 仓库代码替换 <span class="tag ok">已完成</span>(单一真相源 + codegen)</h2>
|
||||
<div class="card ok"><p class="small"><b>已落地,且不再是「散落硬编码」。</b>签名身份收敛成<strong>单一真相源</strong>,今后迁账号/改 Bundle ID <strong>只改一个文件跑一次 codegen</strong>,不用再全仓找替换。</p></div>
|
||||
|
||||
<h3>3.1 Team ID <code>BYL4KQHMTN</code> → <code><NEW_TEAM></code></h3>
|
||||
<table>
|
||||
<tr><th>文件</th><th>处</th></tr>
|
||||
<tr><td><code>scripts/local_test.sh</code></td><td><code>TEAM_ID</code> + 签名主体串</td></tr>
|
||||
<tr><td><code>scripts/ci/compile-macos.sh</code></td><td><code>TEAM_ID=</code>(App Group 由它派生)</td></tr>
|
||||
<tr><td><code>scripts/ci/compile-ios.sh</code></td><td><code>TEAM_ID=</code></td></tr>
|
||||
<tr><td><code>client/macos/Runner.xcodeproj/project.pbxproj</code></td><td>6× <code>DEVELOPMENT_TEAM</code></td></tr>
|
||||
<tr><td><code>client/ios/Runner.xcodeproj/project.pbxproj</code></td><td>6× <code>DEVELOPMENT_TEAM</code></td></tr>
|
||||
<tr><td><code>client/macos/Runner/Release.entitlements</code></td><td>App Group 值</td></tr>
|
||||
<tr><td><code>client/macos/PacketTunnel/PacketTunnel.entitlements</code></td><td>App Group 值</td></tr>
|
||||
<tr><td><code>client/macos/PacketTunnel/Info.plist</code></td><td><code>NEMachServiceName</code> 前缀</td></tr>
|
||||
<tr><td><code>client/macos/PacketTunnel/PacketTunnelProvider.swift</code></td><td><code>private let appGroup</code></td></tr>
|
||||
</table>
|
||||
<h3>3.1 单一真相源 <code>scripts/signing.env</code></h3>
|
||||
<p>Team ID / 实体名 / Bundle ID / App Group 全在这里(当前已是美国身份:Team <code>44WULXM6SV</code>、<code>Yanmei AI LLC</code>、<code>com.yanmeiai.pangolin</code>)。三个签名脚本(<code>local_test.sh</code> / <code>ci/compile-macos.sh</code> / <code>ci/compile-ios.sh</code>)直接 <code>source</code> 它。</p>
|
||||
|
||||
<h3>3.2 Bundle ID 换新(<code>com.pangolin.*</code> → <code>com.yanmeiai.pangolin[.PacketTunnel]</code>)</h3>
|
||||
<table>
|
||||
<tr><th>文件</th><th>处</th></tr>
|
||||
<tr><td><code>client/macos/Runner.xcodeproj/project.pbxproj</code></td><td><code>PRODUCT_BUNDLE_IDENTIFIER</code>(app / 扩展 / Tests)+ <code>PRODUCT_NAME</code>(扩展 = 标识符,铁律)</td></tr>
|
||||
<tr><td><code>client/ios/Runner.xcodeproj/project.pbxproj</code></td><td><code>PRODUCT_BUNDLE_IDENTIFIER</code>(app + 扩展)</td></tr>
|
||||
<tr><td>macOS/iOS 各 <code>*.entitlements</code></td><td><code>application-identifier</code>、App Group 值、<code>NEMachServiceName</code></td></tr>
|
||||
<tr><td><code>client/ios/{Runner,PacketTunnel}</code> 的 Swift</td><td><code>appGroup</code> 常量(<code>group.com.pangolin.pangolinVpn</code> → <code>group.com.yanmeiai.pangolin</code>)</td></tr>
|
||||
<tr><td>macOS Swift <code>PacketTunnelProvider.swift</code></td><td><code>appGroup</code> 常量</td></tr>
|
||||
<tr><td><code>scripts/ci/compile-macos.sh</code> / <code>compile-ios.sh</code> / <code>local_test.sh</code></td><td>App Bundle ID / SYSEXT Bundle ID 常量</td></tr>
|
||||
</table>
|
||||
<div class="card warn"><p class="small"><b>macOS 扩展铁律:</b><code>PRODUCT_NAME</code> 必须等于扩展 Bundle ID(<code>com.yanmeiai.pangolin.PacketTunnel</code>)——否则 sysext 无法 realize。见 <a href="macos-sysext-realize-troubleshooting.html">macOS sysext 排障复盘</a>。</p></div>
|
||||
<h3>3.2 原生文件由 codegen 回填</h3>
|
||||
<p>Xcode/Swift 侧的标识符无法 source 变量、只能字面量,故由 <code>node scripts/gen-signing.mjs</code> 从 signing.env <strong>结构化回填</strong> 16 个原生文件(两端 <code>project.pbxproj</code> 的 <code>DEVELOPMENT_TEAM</code>/Bundle ID、各 <code>*.entitlements</code> 的 App Group/app-identifier、macOS <code>Info.plist</code> 的 <code>NEMachServiceName</code>、各 Swift 的 <code>appGroup</code>/subsystem/loginHelper 等)。codegen 用「形状」匹配、<strong>不含任何旧字面值</strong>——自身无痕,未来再迁仍生效。</p>
|
||||
<pre><span class="c"># 迁账号/改 Bundle ID 的唯一操作:</span>
|
||||
vim scripts/signing.env <span class="c"># 改 3 个基值</span>
|
||||
node scripts/gen-signing.mjs <span class="c"># 回填全部原生文件</span></pre>
|
||||
|
||||
<h3>3.3 实体名 → Yanmei AI LLC</h3>
|
||||
<p><code>scripts/local_test.sh</code> 3 行签名主体串(<code>SIGN_ID</code>、<code>IOS_EXPECT_SIGNER</code>、注释)改成 1.4 你发我的证书精确全名。二进制里的签名主体来自证书,换证后自动为美国实体;这几行只是本机签名/自检时的匹配串。</p>
|
||||
<h3>3.3 drift 闸防漂移</h3>
|
||||
<p><code>ci/check-codegen-drift.sh</code> 跑 <code>gen-signing.mjs --check</code>:若改了 signing.env 没重生成、或手改了原生标识符,即失败。与 token/l10n 同一套 codegen 单源治理。</p>
|
||||
|
||||
<h3>3.4 文档去痕(可选但符合「无痕」要求)</h3>
|
||||
<p><code>docs/</code> 下多份历史文档写死了 <code>BYL4KQHMTN</code> 与中国实体名。这些是内部文档不进产物,但为彻底无痕,我会在同一批把 docs/ 里的 Team ID / 实体名一并改为新值或标注「已迁移」。</p>
|
||||
<h3>3.4 已验证</h3>
|
||||
<ul>
|
||||
<li>6 份 entitlements/plist <code>plutil -lint</code> 全 OK;两端 <code>project.pbxproj</code> <code>xcodebuild -list</code> 可解析,Runner build settings 解析为新 Team/Bundle。</li>
|
||||
<li><code>gen-signing.mjs --check</code> 幂等 0 drift;完整 codegen drift 闸(token/l10n/proto-i18n/signing)全绿。</li>
|
||||
<li>实体名(证书主体来自证书本身,换证后二进制即美国实体)+ 注释/ORGANIZATIONNAME 等 Apple 侧残留痕迹已清。</li>
|
||||
</ul>
|
||||
<div class="card warn"><p class="small"><b>范围说明:</b>未动 Android 包名 <code>com.pangolin.pangolin_vpn</code>(Play Store 身份、自签名、<strong>非 Apple 账号痕迹</strong>,改动会破坏 Play 更新,另议)与 Windows/桌面少量元数据串。<code>codesign</code> 层面 Apple 产物已零中国痕迹。</p></div>
|
||||
|
||||
<h2>4 · gitea Secrets 换新 <span class="tag you">你做</span></h2>
|
||||
<p>gitea → 仓库 <code>wangjia/pangolin</code> → Settings → Actions → <b>Secrets</b>(注意历史经验:Apple 签名 secret 配在 <strong>用户级</strong>非仓库级,见记忆 <code>pangolin-apple-signing-assets</code>——按你当初配的层级更新)。<strong>名字不变,只换值</strong>:</p>
|
||||
@@ -202,17 +190,17 @@
|
||||
<li><b>CI 发版:</b>打 tag <code>client-vX.Y.Z</code> 触发 gitea 流水线,用新 secret 构建。首次建议先跑一次看签名步骤绿。</li>
|
||||
<li><b>无痕核验:</b>对产物二进制跑:
|
||||
<pre>codesign -dvvv <span class="c"># 看 Authority / TeamIdentifier</span> Runner.app 2>&1 | grep -E "Authority|TeamIdentifier"
|
||||
<span class="c"># 期望:Yanmei AI LLC + <NEW_TEAM>,无 BYL4KQHMTN / beijing</span></pre>
|
||||
<span class="c"># 期望:Yanmei AI LLC + 44WULXM6SV,无 BYL4KQHMTN / beijing</span></pre>
|
||||
再全仓 <code>grep -rn "BYL4KQHMTN\|beijing" client scripts .gitea</code> 应为空。</li>
|
||||
</ol>
|
||||
|
||||
<div class="card ok">
|
||||
<h3>✅ 无痕验收清单</h3>
|
||||
<ul>
|
||||
<li>产物二进制 <code>codesign -dvvv</code>:Authority = <code>Yanmei AI LLC</code>、TeamIdentifier = <code><NEW_TEAM></code>。</li>
|
||||
<li>产物二进制 <code>codesign -dvvv</code>:Authority = <code>Yanmei AI LLC</code>、TeamIdentifier = <code>44WULXM6SV</code>。</li>
|
||||
<li><code>grep -rn "BYL4KQHMTN" client scripts .gitea docs</code> → 空。</li>
|
||||
<li><code>grep -rin "beijing\|岩美" client scripts .gitea</code> → 空。</li>
|
||||
<li>Info.plist / entitlements 里 App Group / NEMachServiceName 全为 <code><NEW_TEAM>.com.yanmeiai.pangolin*</code>。</li>
|
||||
<li>Info.plist / entitlements 里 App Group / NEMachServiceName 全为 <code>44WULXM6SV.com.yanmeiai.pangolin*</code>。</li>
|
||||
<li>gitea 12 个 Apple secret 全为新值;旧 p12/profile 不再被任何 workflow 引用。</li>
|
||||
<li>公证记录归属新账号(notarytool history 显示新 Team)。</li>
|
||||
</ul>
|
||||
@@ -224,7 +212,7 @@
|
||||
<tr><td>1</td><td>Apple 后台建 Team/App ID/Group/证书/Profile/ASC Key(§1)</td><td><span class="tag you">你</span></td><td>—</td></tr>
|
||||
<tr><td>2</td><td>把 Team ID + 两张证书全名 + ASC Key 信息发我</td><td><span class="tag you">你</span></td><td>1</td></tr>
|
||||
<tr><td>3</td><td>本机钥匙串核对 + 建 <code>pangolin-notary</code> 公证凭据(§2)</td><td><span class="tag me">我</span></td><td>2</td></tr>
|
||||
<tr><td>4</td><td>仓库代码全量替换(§3)+ 构建自检</td><td><span class="tag me">我</span></td><td>2</td></tr>
|
||||
<tr><td>4</td><td>仓库代码替换 → signing.env 单源 + codegen(§3)<span class="tag ok">已完成</span></td><td><span class="tag me">我</span></td><td>—</td></tr>
|
||||
<tr><td>5</td><td>gitea 12 个 secret 换新值(§4)</td><td><span class="tag you">你</span></td><td>1</td></tr>
|
||||
<tr><td>6</td><td>本机 macOS/iOS 构建验证(§5.1–5.2)</td><td><span class="tag me">我</span></td><td>3,4</td></tr>
|
||||
<tr><td>7</td><td>打 tag 触发 CI 发版 + 无痕核验(§5.3–5.4)</td><td><span class="tag me">我</span>+<span class="tag you">你</span></td><td>4,5</td></tr>
|
||||
|
||||
Reference in New Issue
Block a user