mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-01 15:43:45 +00:00
build(signing): 签名身份按 config 注入,Debug 免证书构建
证书与 Team 不入库(开源仓库):Debug 基线改为 ad-hoc,新 clone 与 CI 无 需任何证书即可 task build / task test;Release 基线保持 Developer ID,发 布产物仍须真签名。本机身份由 gitignore 的 Configs/Signing.local.xcconfig 注入,打包门槛的 Team 期望值同源,缺失时明确失败而非静默跳过。 project.yml 不能再设置 CODE_SIGN_IDENTITY / DEVELOPMENT_TEAM:pbxproj 构 建设置优先于 project xcconfig,写死会静默盖掉基线(实测)。整条注入链条 由 Tests/Architecture/SigningConfigurationTests.swift 守卫。 ad-hoc 产物不带 Hardened Runtime(Xcode 对 ad-hoc 签名不传 -o runtime), 嵌套 helper 重签与之一致;Hardened Runtime 仍由 DevID 路径与打包门槛断言。
This commit is contained in:
@@ -96,6 +96,8 @@ ShadowsocksX-NG2/DerivedData/
|
||||
####
|
||||
# NG2 generated build files (project.yml is the source of truth; run `xcodegen generate`)
|
||||
ShadowsocksX-NG2/*.xcodeproj
|
||||
# 本机签名身份(DEVELOPMENT_TEAM),构建期由 Configs/Signing.xcconfig 可选包含
|
||||
ShadowsocksX-NG2/Configs/Signing.local.xcconfig
|
||||
ShadowsocksX-NG2/App/Resources/Info.plist
|
||||
ShadowsocksX-NG2/App/Resources/ShadowsocksX-NG2.entitlements
|
||||
ShadowsocksX-NG2/Tests/Info.plist
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Debug 签名基线:无证书即可构建(贡献者与 CI)。
|
||||
//
|
||||
// 基线是 ad-hoc(`-`)。arm64 上代码至少要有一层有效签名才会被加载,所以「免证书」
|
||||
// 不能靠不签名,只能靠 ad-hoc。ad-hoc 产物可以构建、可以跑 app、可以跑全部单测,
|
||||
// 但过不了 Scripts/packaging-gate.sh —— 那是有证书的发布门槛。
|
||||
//
|
||||
// 有证书的人(含维护者)在 Configs/Signing.local.xcconfig 里显式升级,例如:
|
||||
//
|
||||
// DEVELOPMENT_TEAM = <10 位 Apple Developer Team ID>
|
||||
// CODE_SIGN_IDENTITY = Developer ID Application
|
||||
//
|
||||
// 该本机文件在 .gitignore 中,不入库;CI 不需要它。
|
||||
//
|
||||
// `#include?` 必须留在最后一行:xcconfig 中后出现的赋值优先,本机文件才能盖掉
|
||||
// 上面的 ad-hoc 基线。
|
||||
CODE_SIGN_IDENTITY = -
|
||||
#include? "Signing.local.xcconfig"
|
||||
@@ -0,0 +1,12 @@
|
||||
// Release 签名基线:发布产物必须是 Developer ID 真签名(Hardened Runtime、公证与
|
||||
// Gatekeeper 的前提),因此这里不给免证书路径。
|
||||
//
|
||||
// Team 只能来自本机注入的 Configs/Signing.local.xcconfig(gitignore)。缺失时
|
||||
// DEVELOPMENT_TEAM 为空,Xcode 以「Signing for ... requires selecting either a
|
||||
// development team or a provisioning profile」使构建明确失败,不会静默降级成
|
||||
// ad-hoc。
|
||||
//
|
||||
// `#include?` 放在 Developer ID 之前:本机文件可以补 Team(另一个键),但不能把
|
||||
// 发布身份改成 ad-hoc 或开发证书——Release 基线在这里是硬约束,后赋值者胜。
|
||||
#include? "Signing.local.xcconfig"
|
||||
CODE_SIGN_IDENTITY = Developer ID Application
|
||||
@@ -59,8 +59,22 @@ ShadowsocksX-NG 的现代化重写版本。新工程的全部源码与构建配
|
||||
## 签名与运行形态基线
|
||||
|
||||
- bundle id `com.qiuyuzhou.ShadowsocksX-NG2`,与 Legacy(`com.qiuyuzhou.ShadowsocksX-NG`)区分;运行时数据落 `~/Library/Application Support/ShadowsocksX-NG2/`。macOS 15+ / arm64。
|
||||
- Hardened Runtime + Developer ID 签名(`DEVELOPMENT_TEAM` / 证书见 `project.yml`);不启用 App Sandbox,entitlements 为空 dict。
|
||||
- 测试 target 用 Apple Development 证书签名:宿主 app 开启 Hardened Runtime 后 library validation 要求被注入的 xctest 包同 Team 签名。
|
||||
- Hardened Runtime(DevID 发布路径;免证书的 ad-hoc Debug 例外,见下);不启用 App Sandbox,entitlements 为空 dict;签名样式固定 `Manual`。
|
||||
- **证书与 Team 都不入库**(开源仓库):`project.yml` 不含 `CODE_SIGN_IDENTITY` / `DEVELOPMENT_TEAM`,两个键由 project xcconfig 按 config 在构建期注入:
|
||||
- `Configs/Signing-Debug.xcconfig`(入库)基线是 **ad-hoc(`-`)**:新 clone 与 CI 不需要任何证书就能 `task build` / `task test`。arm64 要求代码至少有 ad-hoc 签名才会被加载,所以「免证书」不是「不签名」。ad-hoc 产物不带 Hardened Runtime(Xcode 对 ad-hoc 签名不传 `-o runtime`,实测;`Scripts/sign-embedded-helpers.sh` 的 ad-hoc 分支同样不加),Hardened Runtime 由 DevID 发布路径与打包门槛断言。
|
||||
- `Configs/Signing-Release.xcconfig`(入库)基线是 **Developer ID Application**:发布产物必须真签名,这里不给免证书路径。
|
||||
- 两者都可选包含 `Configs/Signing.local.xcconfig`(gitignore)。有证书的人(含维护者)用它升级本机身份,例如让 Debug 也走 Developer ID:
|
||||
|
||||
```bash
|
||||
cat > Configs/Signing.local.xcconfig <<'EOF'
|
||||
DEVELOPMENT_TEAM = YOUR_TEAM_ID
|
||||
CODE_SIGN_IDENTITY = Developer ID Application
|
||||
EOF
|
||||
```
|
||||
|
||||
- 该文件缺失时 Debug 构建为 ad-hoc(可跑单测),Release 构建以 Xcode 的「Signing for … requires selecting either a development team or a provisioning profile」明确失败,不静默降级。
|
||||
- 测试 target(单测与冒烟)身份随同一基线:去宿主化(ADR-0021)后 xctest 包不再注入宿主 app,ad-hoc 也能加载执行(实测),因此测试无需证书。
|
||||
- 注意 `project.yml` 一旦重新设置这两个键,pbxproj 构建设置会盖掉 xcconfig(`Tests/Architecture/SigningConfigurationTests.swift` 守卫该约束)。
|
||||
- Release 配置关闭 `CODE_SIGN_INJECT_BASE_ENTITLEMENTS`,保证发布产物 entitlements 只来自项目文件。
|
||||
|
||||
## 开发、构建与测试
|
||||
@@ -86,6 +100,8 @@ Scripts/fetch-external-binaries.sh
|
||||
task gen:prj
|
||||
```
|
||||
|
||||
无证书也能构建与跑单测:Debug 基线是 ad-hoc,不需要 `Configs/Signing.local.xcconfig`。只有要做 Developer ID 签名(发布,或让本机 Debug 产物过打包门槛)时才写该文件,内容见上节「签名与运行形态基线」。
|
||||
|
||||
`Tests/Smoke/` 是真实进程冒烟(经 wrapper 拉起真实 sslocal 验证启动、握手、
|
||||
ACL 路由与插件监管),不在默认 `task test` 内,由独立 scheme 按需运行。
|
||||
|
||||
@@ -98,6 +114,8 @@ Scripts/packaging-gate.sh \
|
||||
.build/derivedData/Build/Products/Debug/ShadowsocksX-NG2.app
|
||||
```
|
||||
|
||||
打包门槛只接受 Developer ID 签名的产物:Team 期望值取自 `Configs/Signing.local.xcconfig`(可用 `EXPECTED_TEAM_ID=<Team ID>` 显式覆盖),两者都没有时该断言直接失败,不静默跳过。无证书的 ad-hoc Debug 产物会在此明确失败(`gate: hint` 会说明原因),这是预期行为。
|
||||
|
||||
## 代码风格工具
|
||||
|
||||
- `swift format` 随 Xcode/Swift 工具链提供,无需单独安装(基线:Apple Swift 6.4);SwiftLint 需 `brew install swiftlint`(基线 0.65.0)。工具缺失时,含本目录 Swift 文件的提交会被 pre-commit 钩子拒绝而不是放行。
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# 4. The manifest set exactly covers every Mach-O under Contents/Helpers.
|
||||
#
|
||||
# Usage: Scripts/packaging-gate.sh path/to/ShadowsocksX-NG2.app
|
||||
# EXPECTED_TEAM_ID overrides the pinned Team ID check.
|
||||
# EXPECTED_TEAM_ID overrides the Team ID read from the local signing config.
|
||||
|
||||
set -u
|
||||
|
||||
@@ -21,8 +21,20 @@ SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
|
||||
NG2_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
|
||||
VENDOR_DIR="$NG2_ROOT/Vendor"
|
||||
# Mirrors DEVELOPMENT_TEAM in project.yml.
|
||||
EXPECTED_TEAM_ID=${EXPECTED_TEAM_ID:-S878RH3PA8}
|
||||
|
||||
# Expected Team ID is injected, not pinned in the repo (open source). The same
|
||||
# file the build reads supplies it here: Configs/Signing.local.xcconfig
|
||||
# (gitignored). An explicit EXPECTED_TEAM_ID wins. Knowing no expected team is a
|
||||
# hard failure: an unsigned or wrong-team bundle must not pass just because
|
||||
# there is nothing to compare against.
|
||||
LOCAL_SIGNING_CONFIG="$NG2_ROOT/Configs/Signing.local.xcconfig"
|
||||
EXPECTED_TEAM_ID=${EXPECTED_TEAM_ID:-}
|
||||
if [ -z "$EXPECTED_TEAM_ID" ] && [ -f "$LOCAL_SIGNING_CONFIG" ]; then
|
||||
EXPECTED_TEAM_ID=$(
|
||||
sed -n 's/^[[:space:]]*DEVELOPMENT_TEAM[[:space:]]*=[[:space:]]*\([^[:space:]]*\).*/\1/p' \
|
||||
"$LOCAL_SIGNING_CONFIG" | tail -1
|
||||
)
|
||||
fi
|
||||
|
||||
APP=${1:-}
|
||||
[ -n "$APP" ] || {
|
||||
@@ -81,9 +93,19 @@ app_team=$(dv_value "$app_dv" TeamIdentifier)
|
||||
app_authority=$(dv_value "$app_dv" Authority)
|
||||
app_flags=$(dv_value "$app_dv" flags)
|
||||
|
||||
[ "$app_team" = "$EXPECTED_TEAM_ID" ] ||
|
||||
fail "main app TeamIdentifier is $EXPECTED_TEAM_ID (got: ${app_team:-none})"
|
||||
if [ -z "$EXPECTED_TEAM_ID" ]; then
|
||||
fail "expected Team ID is known (set EXPECTED_TEAM_ID or write DEVELOPMENT_TEAM in Configs/Signing.local.xcconfig)"
|
||||
else
|
||||
[ "$app_team" = "$EXPECTED_TEAM_ID" ] ||
|
||||
fail "main app TeamIdentifier is $EXPECTED_TEAM_ID (got: ${app_team:-none})"
|
||||
fi
|
||||
check_devid_and_runtime "main app" "$app_dv"
|
||||
case "$app_authority" in
|
||||
"Developer ID Application:"*) ;;
|
||||
*)
|
||||
echo "gate: hint ad-hoc / non-Developer-ID artifacts come from the certificate-less Debug baseline; only a Developer ID signed release artifact can pass"
|
||||
;;
|
||||
esac
|
||||
|
||||
app_entitlements=$(codesign -d --entitlements - --xml "$APP" 2>/dev/null || true)
|
||||
for forbidden in com.apple.security.app-sandbox com.apple.security.network.server; do
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
# Re-sign every embedded helper binary with the Developer ID identity before
|
||||
# Xcode signs the app itself (spec #21 D6/D10).
|
||||
#
|
||||
# Upstream ships these binaries ad-hoc signed; they must carry our Developer ID
|
||||
# signature with Hardened Runtime and a stable code-signing identifier so the
|
||||
# outer app seal, notarization and Gatekeeper cover them. Xcode runs this as a
|
||||
# post-build script phase and applies the app's own signature afterwards, so
|
||||
# the outer signature embeds the re-signed nested code.
|
||||
# Upstream ships these binaries ad-hoc signed; they must carry a signature with
|
||||
# Hardened Runtime and a stable code-signing identifier so the outer app seal,
|
||||
# notarization and Gatekeeper cover them. Xcode runs this as a post-build script
|
||||
# phase and applies the app's own signature afterwards, so the outer signature
|
||||
# embeds the re-signed nested code.
|
||||
#
|
||||
# The identity comes from the build configuration: Developer ID on a release
|
||||
# build, ad-hoc ("-") on the certificate-less Debug baseline. Ad-hoc mirrors
|
||||
# Xcode's own ad-hoc signing: no secure timestamp and no Hardened Runtime (Xcode
|
||||
# omits -o runtime for ad-hoc; hardened runtime with an untrusted identity would
|
||||
# only get in the way of local debugging). The release path is unchanged.
|
||||
#
|
||||
# The identifier scheme is pinned in the manifests: <bundle-id>.<name> for
|
||||
# sslocal, <bundle-id>.plugin.<name> for SIP003 plugins.
|
||||
@@ -45,7 +51,11 @@ for manifest in $manifests; do
|
||||
exit 1
|
||||
}
|
||||
|
||||
codesign --force --sign "$IDENTITY" --timestamp --options runtime \
|
||||
--identifier "$identifier" "$target"
|
||||
if [ "$IDENTITY" = "-" ]; then
|
||||
codesign --force --sign - --identifier "$identifier" "$target"
|
||||
else
|
||||
codesign --force --sign "$IDENTITY" --timestamp --options runtime \
|
||||
--identifier "$identifier" "$target"
|
||||
fi
|
||||
echo "sign($binary): $identifier"
|
||||
done
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
|
||||
/// 签名身份注入守卫:证书与 Team 都不入库(开源仓库),由 config 基线 + 本机
|
||||
/// xcconfig 在构建期决定。
|
||||
///
|
||||
/// 这条约束容易被无声破坏:`project.yml` 一旦重新设置 `DEVELOPMENT_TEAM` 或
|
||||
/// `CODE_SIGN_IDENTITY`,pbxproj 里的构建设置会盖掉 `Configs/Signing-*.xcconfig`
|
||||
/// (Xcode 构建设置优先级,实测),注入失效却不报错。本套用例把整条链条钉住:
|
||||
/// 工程定义不碰签名键 → config 基线各自正确且本机文件能(或不能)盖掉它 →
|
||||
/// 本机文件不入库 → 供应链脚本与发布门槛跟着基线走。
|
||||
struct SigningConfigurationTests {
|
||||
private static let ng2Root = TestSourceTree.ng2Root()
|
||||
private static let repositoryRoot = ng2Root.deletingLastPathComponent()
|
||||
|
||||
/// 逐行匹配:`String.CompareOptions` 没有 `.anchorsMatchLines`,整段文本上
|
||||
/// `^`/`$` 只锚定字符串首尾,因此把行切开再套正则。
|
||||
private static func matchingLines(_ pattern: String, in text: String) -> [String] {
|
||||
text.split(separator: "\n", omittingEmptySubsequences: false)
|
||||
.filter { $0.range(of: pattern, options: .regularExpression) != nil }
|
||||
.map(String.init)
|
||||
}
|
||||
|
||||
private static func firstLineIndex(matching pattern: String, in text: String) -> Int? {
|
||||
text.split(separator: "\n", omittingEmptySubsequences: false)
|
||||
.firstIndex { $0.range(of: pattern, options: .regularExpression) != nil }
|
||||
}
|
||||
|
||||
private static func text(_ relativePath: String) throws -> String {
|
||||
try String(contentsOf: ng2Root.appendingPathComponent(relativePath), encoding: .utf8)
|
||||
}
|
||||
|
||||
/// 只命中 YAML 键(行首为 `KEY:`),注释行以 `#` 开头,不算设置。
|
||||
private static func yamlKeyPattern(_ key: String) -> String { #"^\s*\#(key)\s*:"# }
|
||||
|
||||
private static let identityAssignment = #"^\s*CODE_SIGN_IDENTITY\s*="#
|
||||
private static let localInclude = #"^\s*#include\?\s+"Signing\.local\.xcconfig"#
|
||||
|
||||
@Test
|
||||
func projectSpecDoesNotPinSigningKeys() throws {
|
||||
let spec = try Self.text("project.yml")
|
||||
for key in ["DEVELOPMENT_TEAM", "CODE_SIGN_IDENTITY"] {
|
||||
let pinned = Self.matchingLines(Self.yamlKeyPattern(key), in: spec)
|
||||
#expect(
|
||||
pinned.isEmpty,
|
||||
"project.yml 不得设置 \(key)(pbxproj 设置会静默盖掉 Configs/Signing-*.xcconfig,且证书/Team 不应入库):\(pinned)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func projectSpecInjectsPerConfigurationBaselines() throws {
|
||||
let spec = try Self.text("project.yml")
|
||||
let expected = [
|
||||
"Debug": "Configs/Signing-Debug.xcconfig",
|
||||
"Release": "Configs/Signing-Release.xcconfig",
|
||||
]
|
||||
for (configuration, path) in expected {
|
||||
let pattern = #"^\s*\#(configuration):\s*\#(path)\s*$"#
|
||||
#expect(
|
||||
!Self.matchingLines(pattern, in: spec).isEmpty,
|
||||
"project.yml 的 configFiles 必须把 \(configuration) 挂到 \(path)")
|
||||
}
|
||||
}
|
||||
|
||||
/// Debug 必须无证书可构建:基线 ad-hoc,且本机文件能把它升级成真证书。
|
||||
@Test
|
||||
func debugBaselineIsAdHocAndUpgradableByLocalFile() throws {
|
||||
let config = try Self.text("Configs/Signing-Debug.xcconfig")
|
||||
#expect(
|
||||
Self.matchingLines(#"^\s*CODE_SIGN_IDENTITY\s*=\s*-\s*$"#, in: config).count == 1,
|
||||
"Configs/Signing-Debug.xcconfig 必须恰好有一条 ad-hoc(-)CODE_SIGN_IDENTITY 基线")
|
||||
let baseline = try #require(
|
||||
Self.firstLineIndex(matching: Self.identityAssignment, in: config),
|
||||
"Configs/Signing-Debug.xcconfig 缺少 CODE_SIGN_IDENTITY 基线")
|
||||
let include = try #require(
|
||||
Self.firstLineIndex(matching: Self.localInclude, in: config),
|
||||
"Configs/Signing-Debug.xcconfig 必须包含 Configs/Signing.local.xcconfig")
|
||||
#expect(
|
||||
baseline < include,
|
||||
"Debug 的 #include? 必须在 ad-hoc 基线之后:xcconfig 后赋值者胜,本机文件才能升级身份")
|
||||
}
|
||||
|
||||
/// Release 必须真签名:本机文件只能补 Team,不能把发布身份改成 ad-hoc。
|
||||
@Test
|
||||
func releaseBaselineStaysDeveloperID() throws {
|
||||
let config = try Self.text("Configs/Signing-Release.xcconfig")
|
||||
let assignments = Self.matchingLines(Self.identityAssignment, in: config)
|
||||
#expect(
|
||||
assignments.last?.contains("Developer ID Application") == true,
|
||||
"Configs/Signing-Release.xcconfig 最后生效的 CODE_SIGN_IDENTITY 必须是 Developer ID Application:\(assignments)"
|
||||
)
|
||||
let include = try #require(
|
||||
Self.firstLineIndex(matching: Self.localInclude, in: config),
|
||||
"Configs/Signing-Release.xcconfig 必须包含 Configs/Signing.local.xcconfig")
|
||||
let baseline = try #require(
|
||||
Self.firstLineIndex(matching: Self.identityAssignment, in: config),
|
||||
"Configs/Signing-Release.xcconfig 缺少 CODE_SIGN_IDENTITY 基线")
|
||||
#expect(include < baseline, "Release 的 #include? 必须在 Developer ID 基线之前,发布身份不被本机文件削弱")
|
||||
}
|
||||
|
||||
@Test
|
||||
func committedBaselinesDoNotPinTeamID() throws {
|
||||
for path in ["Configs/Signing-Debug.xcconfig", "Configs/Signing-Release.xcconfig"] {
|
||||
let config = try Self.text(path)
|
||||
#expect(
|
||||
Self.matchingLines(#"^\s*DEVELOPMENT_TEAM\s*="#, in: config).isEmpty,
|
||||
"入库的 \(path) 不得固化 DEVELOPMENT_TEAM")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func localSigningConfigIsGitIgnored() throws {
|
||||
let ignoreList = try String(
|
||||
contentsOf: Self.repositoryRoot.appendingPathComponent(".gitignore"), encoding: .utf8)
|
||||
#expect(
|
||||
ignoreList.contains("ShadowsocksX-NG2/Configs/Signing.local.xcconfig"),
|
||||
".gitignore 必须忽略 Configs/Signing.local.xcconfig(本机证书/Team 不入库)")
|
||||
}
|
||||
|
||||
/// 嵌套二进制重签必须跟着基线走:ad-hoc 构建没有 secure timestamp。
|
||||
@Test
|
||||
func embeddedHelperSigningHandlesAdHocIdentity() throws {
|
||||
let script = try Self.text("Scripts/sign-embedded-helpers.sh")
|
||||
#expect(
|
||||
!Self.matchingLines(#"--sign -"#, in: script).isEmpty,
|
||||
"sign-embedded-helpers.sh 必须有无证书(ad-hoc)分支,否则 Debug 基线无法封套嵌套二进制")
|
||||
}
|
||||
|
||||
/// 发布门槛的 Team 期望值同样不许写死:只能取自同一个注入文件或显式环境变量。
|
||||
@Test
|
||||
func packagingGateDerivesTeamIDFromInjectedConfig() throws {
|
||||
let gate = try Self.text("Scripts/packaging-gate.sh")
|
||||
#expect(
|
||||
gate.contains("Signing.local.xcconfig"),
|
||||
"packaging-gate.sh 必须从 Configs/Signing.local.xcconfig 读取期望 Team ID")
|
||||
#expect(
|
||||
Self.matchingLines(#":-[A-Z0-9]{10}\}"#, in: gate).isEmpty,
|
||||
"packaging-gate.sh 不得给 Team ID 留 10 位写死的默认值")
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,22 @@ settings:
|
||||
# 自动抽取会在 IDE 构建时膨胀文件(2026-10-04 #81 验收时实测)。
|
||||
LOCALIZED_STRING_SWIFTUI_SUPPORT: NO
|
||||
CODE_SIGN_STYLE: Manual
|
||||
DEVELOPMENT_TEAM: S878RH3PA8
|
||||
ENABLE_HARDENED_RUNTIME: YES
|
||||
configs:
|
||||
Release:
|
||||
# 发布基线:签名 entitlements 必须只来自项目 entitlements 文件(保持最小)。
|
||||
CODE_SIGN_INJECT_BASE_ENTITLEMENTS: NO
|
||||
# 签名身份注入:证书与 Team 都不入库(开源仓库;写死会让 fork 与贡献者的构建去
|
||||
# 找维护者的证书)。Debug 基线是 ad-hoc,无证书即可构建并跑单测;Release 基线是
|
||||
# Developer ID,发布产物必须真签名。两者的本机 Team / 身份都来自 gitignore 的
|
||||
# Configs/Signing.local.xcconfig,见 Configs/Signing-Debug.xcconfig 与
|
||||
# Configs/Signing-Release.xcconfig。
|
||||
# 所有 target 一律不设置 CODE_SIGN_IDENTITY:pbxproj 构建设置优先于 project
|
||||
# xcconfig,写在 target 上会静默盖掉两个基线(实测)。该约束由
|
||||
# Tests/Architecture/SigningConfigurationTests.swift 守卫。
|
||||
configFiles:
|
||||
Debug: Configs/Signing-Debug.xcconfig
|
||||
Release: Configs/Signing-Release.xcconfig
|
||||
targets:
|
||||
ShadowsocksX-NG2:
|
||||
type: application
|
||||
@@ -110,7 +120,6 @@ targets:
|
||||
# 共享 Products 目录,重名会互相覆盖;app 可执行自身不 import 任何
|
||||
# 消费方,改名零影响。
|
||||
PRODUCT_MODULE_NAME: ShadowsocksX_NG2App
|
||||
CODE_SIGN_IDENTITY: "Developer ID Application"
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
|
||||
MARKETING_VERSION: "2.0.0"
|
||||
# 必须 > 旧版 1.x 已发布构建的 CFBundleVersion(始终为 1),保证 build 号严格递增。
|
||||
@@ -194,7 +203,6 @@ targets:
|
||||
base:
|
||||
PRODUCT_NAME: ShadowsocksX-NG2Agent
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.qiuyuzhou.ShadowsocksX-NG2.agent
|
||||
CODE_SIGN_IDENTITY: "Developer ID Application"
|
||||
ShadowsocksX-NG2SystemProxyHelper:
|
||||
type: tool
|
||||
platform: macOS
|
||||
@@ -213,7 +221,6 @@ targets:
|
||||
base:
|
||||
PRODUCT_NAME: ShadowsocksX-NG2SystemProxyHelper
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.qiuyuzhou.ShadowsocksX-NG2.systemproxy.helper
|
||||
CODE_SIGN_IDENTITY: "Developer ID Application"
|
||||
ShadowsocksX-NG2Tests:
|
||||
type: bundle.unit-test
|
||||
platform: macOS
|
||||
@@ -229,9 +236,9 @@ targets:
|
||||
settings:
|
||||
base:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.qiuyuzhou.ShadowsocksX-NG2.Tests
|
||||
# 必须与宿主 app 同 Team 签名:Hardened Runtime 的 library validation 拒绝
|
||||
# 加载不同 Team ID 的非平台库,ad-hoc("-")签名的 xctest 包无法注入。
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
# 身份随 config 基线走(Debug ad-hoc / Release DevID,见 configFiles):
|
||||
# 去宿主化(ADR 0021)后 xctest 包不再注入宿主 app,ad-hoc 可加载执行
|
||||
# (实测),因此测试不再需要证书,CI 无需签名密钥。
|
||||
info:
|
||||
path: Tests/Info.plist
|
||||
properties: {}
|
||||
@@ -250,8 +257,7 @@ targets:
|
||||
settings:
|
||||
base:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.qiuyuzhou.ShadowsocksX-NG2.SmokeTests
|
||||
# 同 Team 签名理由同 ShadowsocksX-NG2Tests。
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
# 身份理由同 ShadowsocksX-NG2Tests:随 config 基线,Debug 无证书可跑。
|
||||
info:
|
||||
path: Tests/Smoke/Info.plist
|
||||
properties: {}
|
||||
|
||||
Reference in New Issue
Block a user