refactor(signing): shell 签名身份抽成单一真相源 scripts/signing.env

迁移美国账号引出的诉求:Team ID/实体名/Bundle ID/App Group 原本散在三个签名脚本里
硬编码,迁一次账号要改多处易漏。抽成 scripts/signing.env 单一真相源,三脚本
(local_test.sh / ci/compile-macos.sh / ci/compile-ios.sh)source 它并派生各自常量。

signing.env(非机密,入 git)含:SIGNING_TEAM_ID / SIGNING_ENTITY / SIGNING_APP_BUNDLE_ID
/ SIGNING_EXT_BUNDLE_ID / SIGNING_{MACOS,IOS}_APP_GROUP + 派生的 Developer ID /
Apple Distribution 签名主体串。当前值已是美国 Yanmei AI LLC(Team 44WULXM6SV,
Bundle com.yanmeiai.pangolin);今后迁账号/改 Bundle ID 只改这一个文件。

bash -n 三脚本语法通过;source 冒烟各派生值正确。Xcode 侧单源(Signing.xcconfig)
另提交,由一致性闸比对防两处漂移。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
This commit is contained in:
wangjia
2026-09-06 20:03:43 +08:00
parent 47c1e3329f
commit baaf21df36
4 changed files with 60 additions and 24 deletions
+10 -8
View File
@@ -6,8 +6,8 @@
# cert import, provisioning-profile install by UUID, ExportOptions.plist,
# `flutter build ipa`, `xcrun altool --upload-app`), adapted for pangolin:
# - pangolin's iOS app ships a NEPacketTunnelProvider **app extension**
# (client/ios/PacketTunnel/, bundle com.pangolin.pangolinVpn.PacketTunnel)
# alongside the main app (com.pangolin.pangolinVpn) — jiu has no
# (client/ios/PacketTunnel/, bundle com.yanmeiai.pangolin.PacketTunnel)
# alongside the main app (com.yanmeiai.pangolin) — jiu has no
# extension at all, just the one app target. So this script needs TWO
# distribution provisioning profiles (app + extension), not one, and the
# ExportOptions.plist provisioningProfiles dict needs both bundle-id ->
@@ -17,7 +17,7 @@
# embedded core. This script MUST run `scripts/build-libbox.sh apple ios`
# before `flutter build ipa`, or the IPA links no VPN kernel (mirrors the
# equivalent step in compile-android.sh / compile-macos.sh).
# - Team ID BYL4KQHMTN is hardcoded as a script constant rather than a
# - Team ID 44WULXM6SV is hardcoded as a script constant rather than a
# secret (unlike jiu's IOS_TEAM_ID secret): it's already public inside
# this repo (CLAUDE.md, client/ios/Runner.xcodeproj/project.pbxproj
# DEVELOPMENT_TEAM, scripts/local_test.sh SIGN_ID) — not sensitive, no
@@ -33,9 +33,9 @@
# IOS_DIST_CERT_P12_BASE64 Apple Distribution 证书(.p12)base64
# IOS_DIST_CERT_PASSWORD .p12 导出密码
# IOS_APP_PROVISIONING_PROFILE_BASE64 App Store 类型描述文件(主 app,
# com.pangolin.pangolinVpn)base64
# com.yanmeiai.pangolin)base64
# IOS_PACKETTUNNEL_PROVISIONING_PROFILE_BASE64 App Store 类型描述文件(扩展,
# com.pangolin.pangolinVpn.PacketTunnel)base64
# com.yanmeiai.pangolin.PacketTunnel)base64
# APPSTORE_API_KEY_ID / APPSTORE_API_ISSUER_ID / APPSTORE_API_KEY_P8_BASE64
# App Store Connect API Key(上传 TestFlight 用;与 compile-macos.sh 公证共用)。
#
@@ -83,9 +83,11 @@ fi
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
API_URL="${PANGOLIN_API_URL:-https://api.yanmeiai.com}"
TEAM_ID="BYL4KQHMTN"
APP_BUNDLE_ID="com.pangolin.pangolinVpn"
EXT_BUNDLE_ID="com.pangolin.pangolinVpn.PacketTunnel"
# 签名身份单一真相源(../signing.env);迁移账号只改 signing.env。
. "${BASH_SOURCE[0]%/*}/../signing.env"
TEAM_ID="$SIGNING_TEAM_ID"
APP_BUNDLE_ID="$SIGNING_APP_BUNDLE_ID"
EXT_BUNDLE_ID="$SIGNING_EXT_BUNDLE_ID"
WORK="$(mktemp -d)"
KEYCHAIN="${WORK}/pangolin-ios-ci.keychain-db"
+7 -5
View File
@@ -6,7 +6,7 @@
# Mirrors ~/code/jiu/scripts/ci/compile-macos.sh's shape (temp-keychain
# Developer ID import, inside-out codesign, notarytool submit --wait, staple,
# ditto zip), but pangolin's macOS app is heavier than jiu's plain window:
# - it embeds a System Extension (com.pangolin.pangolin.PacketTunnel,
# - it embeds a System Extension (com.yanmeiai.pangolin.PacketTunnel,
# `.systemextension` bundle under Contents/Library/SystemExtensions/)
# that needs ITS OWN Developer ID provisioning profile + entitlements,
# signed separately, inside-out, before the outer app is signed — see
@@ -92,11 +92,13 @@ echo "==> compile-macos: tag=${TAG} version=${VER} build=${BUILD}"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
API_URL="${PANGOLIN_API_URL:-https://api.yanmeiai.com}"
# 签名身份单一真相源(../signing.env);迁移账号只改 signing.env。
. "${BASH_SOURCE[0]%/*}/../signing.env"
SIGN_ID_PREFIX="Developer ID Application"
TEAM_ID="BYL4KQHMTN"
APP_BUNDLE_ID="com.pangolin.pangolin"
SYSEXT_BUNDLE_ID="com.pangolin.pangolin.PacketTunnel"
APP_GROUP="${TEAM_ID}.com.pangolin.pangolin"
TEAM_ID="$SIGNING_TEAM_ID"
APP_BUNDLE_ID="$SIGNING_APP_BUNDLE_ID"
SYSEXT_BUNDLE_ID="$SIGNING_EXT_BUNDLE_ID"
APP_GROUP="$SIGNING_MACOS_APP_GROUP"
WORK="$(mktemp -d)"
KEYCHAIN="${WORK}/pangolin-mac-ci.keychain-db"
+15 -11
View File
@@ -23,12 +23,16 @@
# 用法: scripts/local_test.sh all | scripts/local_test.sh ipad ...
set -euo pipefail
# 签名身份单一真相源(Team ID / 实体名 / Bundle ID / App Group)——迁移账号只改 signing.env。
_SIGN_ENV_DIR="${BASH_SOURCE[0]%/*}"; [ "$_SIGN_ENV_DIR" = "${BASH_SOURCE[0]}" ] && _SIGN_ENV_DIR="."
. "${_SIGN_ENV_DIR}/signing.env"
# ─────────── 配置(按需改)───────────
# 控制面基址。默认生产(Cloudflare Tunnel);8080 已收口只绑 127.0.0.1,公网直连
# 不再可用——联调自建控制面时用 env 显式覆盖:
# API_URL=http://<联调地址>:8080 scripts/local_test.sh macos
API_URL="${API_URL:-https://api.yanmeiai.com}"
SIGN_ID="Developer ID Application: Yanmei (beijing) Technology Co., Ltd (BYL4KQHMTN)"
SIGN_ID="$SIGNING_DEVELOPER_ID" # 派生自 signing.env
APP_PROFILE_NAME="Pangolin App DevID" # 主 app 的 Developer ID 描述文件名
SE_PROFILE_NAME="Pangolin PacketTunnel DevID" # PacketTunnel 的描述文件名
TEST_EMAIL="wang880812@gmail.com" # 联调测试账号
@@ -40,15 +44,15 @@ IP_SVC="https://api.ipify.org" # 返回纯文本公网 IP
# 注:DevID profile 已含 system-extension.install + NE(-systemextension 变体);
# app/sysext entitlements 与之对齐(见 write_entitlements)。
TEAM_ID="BYL4KQHMTN" # Yanmei (beijing) Technology Co., Ltd
TEAM_ID="$SIGNING_TEAM_ID" # 派生自 signing.env
# macOS App Group —— 必须是原生格式 <TeamID>.<name>,不是 iOS 的 group. 前缀(CLAUDE.md 铁律)。
# 主 app 与 sysext 必须落在**同一个**;sysext 的 NEMachServiceName 必须以它为前缀。
APP_GROUP="${TEAM_ID}.com.pangolin.pangolin"
APP_GROUP="$SIGNING_MACOS_APP_GROUP"
# ── iOS/iPad 真机分发(ad-hoc,**公司**证书)────────────────────────────────
IOS_BUNDLE_ID="com.pangolin.pangolinVpn"
IOS_BUNDLE_ID="$SIGNING_APP_BUNDLE_ID"
# 期望的签名主体。装机前逐字核对,不符即中止 —— 防止悄悄退回个人开发证书。
IOS_EXPECT_SIGNER="Apple Distribution: Yanmei (beijing) Technology Co., Ltd (${TEAM_ID})"
IOS_EXPECT_SIGNER="$SIGNING_APPLE_DISTRIBUTION"
# ─────────── 路径推导 ───────────
SRC="${BASH_SOURCE[0]}"
@@ -57,9 +61,9 @@ cd "$DIR/.."; REPO_ROOT="$PWD"
CLIENT="$REPO_ROOT/client"
PBXPROJ="$CLIENT/macos/Runner.xcodeproj/project.pbxproj"
APP="$CLIENT/build/macos/Build/Products/Release/pangolin_vpn.app"
# sysext bundle 名 = 标识符(PRODUCT_NAME=com.pangolin.pangolin.PacketTunnel,见 CLAUDE.md),
# sysext bundle 名 = 标识符(PRODUCT_NAME=com.yanmeiai.pangolin.PacketTunnel,见 CLAUDE.md),
# 不是短名 PacketTunnel.systemextension。
SE="$APP/Contents/Library/SystemExtensions/com.pangolin.pangolin.PacketTunnel.systemextension"
SE="$APP/Contents/Library/SystemExtensions/${SIGNING_EXT_BUNDLE_ID}.systemextension"
LIBFW="$SE/Contents/Frameworks/Libbox.framework"
PROF_DIR="$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
WORK="${TMPDIR:-/tmp}/pangolin_local_test"; mkdir -p "$WORK"
@@ -90,7 +94,7 @@ write_entitlements(){
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>com.apple.application-identifier</key><string>${TEAM_ID}.com.pangolin.pangolin</string>
<key>com.apple.application-identifier</key><string>${TEAM_ID}.${SIGNING_APP_BUNDLE_ID}</string>
<key>com.apple.developer.team-identifier</key><string>${TEAM_ID}</string>
<key>com.apple.developer.system-extension.install</key><true/>
<key>com.apple.developer.networking.networkextension</key>
@@ -101,14 +105,14 @@ write_entitlements(){
<key>com.apple.security.application-groups</key>
<array><string>${APP_GROUP}</string></array>
<key>keychain-access-groups</key>
<array><string>${TEAM_ID}.com.pangolin.pangolin</string></array>
<array><string>${TEAM_ID}.${SIGNING_APP_BUNDLE_ID}</string></array>
</dict></plist>
PLIST
cat > "$WORK/sysext.entitlements" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>com.apple.application-identifier</key><string>${TEAM_ID}.com.pangolin.pangolin.PacketTunnel</string>
<key>com.apple.application-identifier</key><string>${TEAM_ID}.${SIGNING_EXT_BUNDLE_ID}</string>
<key>com.apple.developer.team-identifier</key><string>${TEAM_ID}</string>
<key>com.apple.developer.networking.networkextension</key>
<array><string>packet-tunnel-provider-systemextension</string></array>
@@ -317,7 +321,7 @@ cmd_ks_status(){
# ─────────── iOS / iPad 真机安装 ───────────
# 与 macOS 流程独立:iOS 用 Network Extension(非 System Extension),不需要 Developer ID
# 重签 / 公证;flutter build ios --release 由 Xcode 工程配置签名(Team=BYL4KQHMTN,自动
# 重签 / 公证;flutter build ios --release 由 Xcode 工程配置签名(Team=44WULXM6SV,自动
# 签名会把已连接设备注册进描述文件),再 flutter install 走 USB 直接装。
# 列出已连接的物理 iOS 设备(输出 "id<TAB>name" 每行一台;模拟器/无线设备排除)。
+28
View File
@@ -0,0 +1,28 @@
# signing.env — Apple 签名身份的【单一真相源】(shell 侧)
#
# 迁移开发者账号 / 改 Bundle ID 时,只改这一个文件;三个签名脚本
# (local_test.sh / ci/compile-macos.sh / ci/compile-ios.sh)全部 source 它,
# 不再各自硬编码。非机密(Team ID / 实体名 / Bundle ID 本就编进产物、公开),入 git。
#
# ⚠️ Xcode 侧另有等价单一真相源 client/Signing.xcconfig(格式不同、内容须一致),
# 由 ci/check-signing-config.sh 一致性闸比对,防两处漂移。改这里也要改那里。
# 10 位 Team ID(developer.apple.com → Membership details)。
SIGNING_TEAM_ID="44WULXM6SV"
# 法人实体名(= 证书主体 CN 内含;Developer ID / Apple Distribution 证书都用它)。
SIGNING_ENTITY="Yanmei AI LLC"
# 主 app Bundle ID(macOS 与 iOS 现共用同串)。
SIGNING_APP_BUNDLE_ID="com.yanmeiai.pangolin"
# PacketTunnel 扩展 Bundle ID(主 app + .PacketTunnel)。
SIGNING_EXT_BUNDLE_ID="${SIGNING_APP_BUNDLE_ID}.PacketTunnel"
# App Group:macOS 用原生 <TeamID>.<bundle> 格式;iOS 用 group.<bundle> 前缀。
SIGNING_MACOS_APP_GROUP="${SIGNING_TEAM_ID}.${SIGNING_APP_BUNDLE_ID}"
SIGNING_IOS_APP_GROUP="group.${SIGNING_APP_BUNDLE_ID}"
# 派生的证书签名主体(codesign -s / 签名核验用)。
SIGNING_DEVELOPER_ID="Developer ID Application: ${SIGNING_ENTITY} (${SIGNING_TEAM_ID})"
SIGNING_APPLE_DISTRIBUTION="Apple Distribution: ${SIGNING_ENTITY} (${SIGNING_TEAM_ID})"