CI/CD 2026.09.18

Swift Package Manager 企业代理怎么配?2026 Mac CI 指南

管理员终端能下载依赖,并不代表 CI 服务账号具备同样的代理、证书和凭证上下文。本文按流量盘点、账号配置、依赖解析、TLS 验证、真实流水线和灰度上线推进,帮助企业团队判断自有 Mac 或远程 Mac 是否适合纳入 Mac CI 节点池。

第一周不要先给 Runner 粗暴设置 HTTP_PROXY。配置 Swift Package Manager 企业代理 时,正确顺序是:先把源码仓库、Swift Package Registry、二进制制品和 Apple 服务分成四类流量,再分别核查 Git、SSH、凭证、内部 CA 与代理例外,最后必须在真实 CI 服务账号和干净工作区中完成验收。

如果某类任务始终无法纳入企业网络策略,应把它放进隔离的远程 Mac 节点池,而不是继续向共享构建机复制管理员环境。

这篇文章适合三类团队:

  • 管理企业代理、防火墙和内部 CA,希望为 Mac 构建节点建立统一出站策略的 IT 负责人。
  • 负责 Xcode 流水线和 Swift 依赖治理,希望消除“本地成功、CI 失败”的平台工程团队。
  • 正在评估自有设备与远程 Mac 节点,希望验证网络兼容性和批量交付能力的技术决策者。

01 第一天:先画出依赖流量地图,再决定代理放在哪里

同一次构建触发了多种工具和认证路径时,失败往往并非由一个代理地址造成。源码控制依赖可能由 Git 处理,SSH 依赖还会读取 ~/.ssh/configknown_hosts;Registry 依赖有自己的 Registry 配置和凭证;二进制 Target 或预构建包又可能走 HTTP 下载路径。Apple 服务则可能拥有独立的证书校验和 HTTPS 检查限制,不能因为内部 Git 能访问,就推断 Apple 服务也能正常工作。

SwiftPM 官方文档明确区分了 Registry 凭证、二进制制品下载凭证和 Git 自身使用的认证体系;其中 SWIFTPM_SOURCE_CONTROL_TOKEN 不负责 git clonegit fetch。(Swift Package Manager Registry 使用说明)

流量类别 主要执行工具 需要单独核查的内容 常见误判
源码控制依赖 Git、SSH、xcodebuild http.proxy、环境变量、SSH 配置、known_hosts Git 能拉代码,就认为 Registry 也可用
Swift Package Registry SwiftPM Registry URL、Token、Keychain 或 .netrc 只给 Git 配置代理
二进制 Target 与预构建包 SwiftPM 的 HTTP 下载路径 SWIFTPM_SOURCE_CONTROL_TOKEN、内部 CA、制品库权限 源码依赖成功后忽略二进制下载
Apple 服务 Xcode、系统服务及相关网络组件 HTTPS 检查例外、证书链、Apple 网络策略 导入企业 CA 后要求所有流量都接受检查

第一天的产物不是一张“允许域名清单”,而是一份可追踪的流量表。每一行至少记录目标类别、实际域名、认证方式、调用工具、运行账号、是否允许代理、是否需要直连或 HTTPS 检查例外。

⚠️ 不要直接复制未经验证的端口、域名或防火墙规则。先在一次干净解析中记录 DNS、连接、TLS 和应用层错误,再让网络团队根据实际日志制定策略。

02 第二天:固定 CI 服务账号,避免管理员终端制造假象

管理员终端能解析依赖,但 CI 服务账号持续超时或报证书错误,通常说明配置落在了错误的作用域。

macOS 系统代理、HTTP_PROXY / HTTPS_PROXY、Git 配置、SSH 配置、Keychain 和 .netrc 并不会自动合并成一套全局环境。管理员登录 Shell 中存在的变量,不会因为 Jenkins、GitHub Actions、GitLab Runner 或其他服务启动了构建任务,就自动出现在服务账号里。

先在真实 Runner 任务中输出非敏感诊断信息:

id
printf 'HOME=%s\n' "$HOME"
env | grep -iE '^(http|https|no)_proxy='
git config --show-origin --get http.proxy
ssh -G git.example.internal | sed -n '1,25p'

这里的 git.example.internal 只是占位符,不能照抄到生产环境。检查重点是:

  • HOME 是否属于实际 CI 服务账号,而不是管理员。
  • Git 配置来自系统级、用户级还是仓库级文件。
  • SSH 实际加载了哪一份配置和密钥。
  • 代理凭证是否通过受控密钥注入,而不是写进命令行、仓库文件或共享脚本。
  • Keychain 项目是否属于服务账号,且无人值守任务确实有权访问。

Git 官方文档说明,Git 可以读取标准代理环境变量,也可以通过 http.proxy 配置代理,并且还能按 URL 范围细分配置。(Git FAQ:代理与网络配置) 这意味着“在管理员账号里设置一次代理”并不能替代服务账号验证。

服务账号怎样获得代理和证书配置?

答案不是“复制管理员目录”。应把代理变量、Git 配置、SSH 配置和内部 CA 作为四类交付对象,分别由 Runner 的受控启动流程加载,并在任务开始时验证来源。个人 Keychain、个人代理凭证和管理员的 ~/.ssh 不应复制到共享节点。

03 第三天:让 xcodebuild 使用正确的 Git 配置

当流水线需要继承系统 Git 的代理、URL 重写或高级 SSH 设置时,使用 Xcode 内置 Git 可能导致本地命令和 CI 行为不一致。

Apple 官方 CI 文档指出,直接调用 xcodebuild 时,可以通过 -scmProvider system 让它使用 Mac 上的系统 Git 及其配置;这对代理配置、URL remapping 和高级 SSH 设置尤其重要。(Apple:在持续集成中构建 Swift 包或使用 Swift 包的 App)

一个只保留关键选项的构建片段如下:

xcodebuild \
  -workspace App.xcworkspace \
  -scheme App \
  -configuration Release \
  -scmProvider system \
  -disableAutomaticPackageResolution \
  archive

其中,-scmProvider system 解决的是 Git 工具和配置来源问题;它不会替你完成 Registry 登录,也不会让 Apple 服务自动绕过企业 HTTPS 检查。

-disableAutomaticPackageResolution 的作用是让 CI 按已提交的 Package.resolved 使用依赖版本,而不是在每次构建中随意更新解析结果。Apple 官方文档建议将 Package.resolved 提交到代码仓库,SwiftPM 官方文档也说明,顶层项目存在该文件时,解析过程会参考其中记录的依赖版本。(Apple:持续集成中的依赖锁定)

验证项 最小验证动作 通过标准
HTTPS Git 在服务账号下执行一次只读拉取 能确认代理来源、目标地址和证书链
SSH Git 使用服务账号读取 SSH 配置并连接仓库 known_hosts 已由企业流程交付,未关闭主机校验
Registry 执行 Registry 解析和下载测试 Registry URL、Token 和账号作用域一致
二进制制品 删除对应缓存后重新下载 下载凭证与源码 Git 凭证分离
依赖锁定 使用干净工作区执行解析 结果与 Package.resolved 一致,不发生未授权更新

怎样让 xcodebuild 读取系统 Git 的代理设置?

先将代理写入实际服务账号可读的 Git 配置,或由 Runner 启动脚本安全注入;再在 xcodebuild 中加入 -scmProvider system。随后用 git config --show-origin --get http.proxy 和一次只读拉取确认配置来源,不要仅凭管理员终端中的 git clone 结果判断成功。

如果源码仓库使用 SSH,Apple 文档要求在执行 CI 任务的 macOS 用户 ~/.ssh 目录中准备 known_hosts,并说明 xcodebuild 会遵循 SSH 配置。(Apple:Xcode 持续集成中的源代码管理)

04 第四天:分别处理 Registry、二进制制品和凭证

Swift Package Registry 不应被当作“另一个 Git 仓库”。SwiftPM 官方 Registry 文档说明,Registry 可以在项目级或用户级配置,凭证可以使用 Keychain、.netrc 或 CI 环境变量;不同凭证来源还存在优先级关系。(Swift Package Manager:Package Registry 使用说明)

企业 CI 更适合采用短时有效、可撤销的 Token,并通过 Runner 的秘密管理机制注入。示例只展示变量名称,不展示真实凭证:

export SWIFTPM_REGISTRY_TOKEN="$CI_REGISTRY_TOKEN"
swift package resolve

如果流水线还要下载 .binaryTarget(url:) 或预构建包,应单独核查 SWIFTPM_SOURCE_CONTROL_TOKEN 的适用范围。它不会替代 Git 的 SSH 密钥、Git Credential Helper 或源码仓库 Token。这个边界如果不提前记录,常见结果就是“源码包能解析,二进制包在归档阶段失败”。

对于需要企业内部 Registry 的项目,还要确认配置到底落在:

  • 项目目录下的 .swiftpm/configuration/registries.json
  • 服务账号的 ~/.swiftpm/configuration/registries.json
  • 还是某次管理员交互登录生成的用户凭证。

如果生产构建依赖服务账号,优先把配置作为节点交付的一部分明确管理,而不是要求每个开发者在远程桌面里手动登录。

05 第五天:把 HTTPS 检查和内部 CA 分成两条验证线

企业网络中的 HTTPS 检查可能让 Swift 包解析失败,但不能把所有证书错误都归因于 HTTPS 检查。失败可能发生在代理转发、TLS 证书链、应用层认证或 SwiftPM 的包校验阶段,四者需要用不同证据区分。

Apple 的企业网络文档明确指出,部分 Apple 服务无法使用 HTTPS Interception,也就是 SSL Inspection;如果流量经过 Web 代理,需要针对适用服务关闭 HTTPS 检查。(Apple:软件更新相关企业网络要求) 因此,企业内部 Git、Registry 和制品库可以按照内部 CA 策略管理,但不能因此推断 Apple 服务都应该接受企业代理重新签发的证书。

建议按下面顺序判断:

  1. 目标域名:确认失败的请求究竟发往 Git、Registry、制品库还是 Apple 服务。
  2. 证书链:记录服务端证书、签发链和 Runner 是否信任对应根证书。
  3. 实际进程:确认是 Git、SwiftPM、xcodebuild 还是其他下载器发起连接。
  4. 代理响应:区分代理拒绝、TLS 握手失败、HTTP 认证失败和包内容校验失败。
  5. 企业策略:让网络团队确认该目标允许直连、普通代理,还是必须排除 HTTPS 检查。

不要用关闭证书校验来验证代理是否可用,例如不要把 git config http.sslVerify false 当作上线方案。Git 官方文档支持通过 http.proxy 和更细粒度的 URL 配置控制代理,但证书校验应保持在企业批准的信任边界内。(Git 配置文档:HTTP 代理与 TLS 选项)

内部 CA 的安装、信任和撤销应由企业设备管理流程完成。远程 Mac 节点如果无法稳定接收 CA 更新,或者重启后无法恢复信任状态,就不适合直接承接生产签名和发布任务。

06 第六天:用干净工作区完成第一条真实流水线

一次“下载成功”不能证明节点已经可上线。建议从无缓存工作区开始,按依赖解析、构建、测试和制品生成四个阶段记录证据。

rm -rf ~/ci-clean-workspace
git clone "$REPOSITORY_URL" ~/ci-clean-workspace
cd ~/ci-clean-workspace

xcodebuild \
  -workspace App.xcworkspace \
  -scheme App \
  -scmProvider system \
  -disableAutomaticPackageResolution \
  clean archive

实际项目应根据工作区、Scheme、签名和归档参数补充必要选项,但不要把个人目录、管理员 Keychain 或临时代理变量直接写入脚本。

验收时至少覆盖以下情况:

  • [ ] 服务账号在干净工作区完成源码获取。
  • [ ] HTTPS Git、SSH Git、Registry 和二进制制品分别完成验证。
  • [ ] Package.resolved 被读取,且构建没有未经批准的依赖更新。
  • [ ] 内部 CA 在服务账号和重启后的节点上仍然有效。
  • [ ] Apple 服务例外已经由网络团队确认,而不是通过关闭校验绕过。
  • [ ] 构建、测试、归档和制品上传均在同一账号上下文中执行。
  • [ ] 节点重启后,代理、Git、SSH、Registry 和 Keychain 状态可以恢复。
  • [ ] 代理凭证轮换后,旧凭证不会继续被脚本或缓存使用。
  • [ ] 代理暂时不可用时,流水线能给出可定位的失败证据。
  • [ ] 需要访问企业内网的任务与只访问公共依赖的任务已经分池。

Apple 的 CI 文档也建议直接调用 xcodebuild 时关闭自动依赖解析,以确保使用锁定结果;这不是为了让网络问题消失,而是为了让网络问题不再和版本漂移混在一起。(Apple:Xcode 持续集成工作流)

07 第七天:先灰度节点,再决定是否扩展远程 Mac

第一周不要直接把所有生产流水线迁移到新节点。可以先让隔离节点承接非生产构建,观察真实依赖解析记录、代理失败日志、服务账号重启恢复和凭证轮换结果。

需要访问企业 Git、内部 Registry 或签名服务的节点,应使用与仅访问公共依赖的弹性节点不同的网络策略。生产签名任务还应继续保持独立信任边界,避免把长期凭证和普通构建任务放在同一共享环境中。

远程 Mac 接入企业 Git 和内部 Package Registry,需要满足哪些条件?

远程 Mac 本身不能绕过企业内网权限。可行方案通常是让节点通过企业批准的出站代理、专用网络通道或受控出口访问内部 Git 和 Registry,并在节点上用真实 CI 服务账号完成同样的流量地图与验收表。

如果现有 Mac 缺少远程恢复能力、无法稳定接收代理策略,或者重启后依赖 Keychain 交互登录,那么继续改造自有设备的成本可能高于增加隔离节点。此时可以先阅读 企业远程 Mac 租赁 PoC 与网络兼容性验收指南,再用同一份验收表测试远程节点,而不是先承诺批量迁移。

节点池可以按三种方式推进:

  • 专用池:企业内网、签名和私有依赖集中在隔离节点,稳定性优先。
  • 弹性池:只承接公共依赖和非签名任务,扩容速度优先。
  • 混合池:专用节点处理敏感任务,远程 Mac 弹性节点承担可迁移的构建任务。

如果团队正在比较节点池形态,可进一步参考 Mac 构建节点的专用池、弹性池与混合容量选型。如果主要问题是私有依赖与签名凭证隔离,则应先完成 企业 iOS CI/CD 私有依赖与签名凭证隔离方案 中的权限边界设计,再讨论节点数量。

08 最终决策:什么时候继续改造自有 Mac,什么时候接入远程 Mac

如果自有 Mac 已经能在真实服务账号下稳定完成代理、内部 CA、私有 Registry、签名和重启恢复,那么继续改造通常更容易纳入现有运维体系。

但如果当前方案存在以下问题,就不适合作为长期扩展基础:

  • 管理员登录后才有代理或 Keychain 权限,服务账号无法无人值守运行。
  • 企业 HTTPS 检查与 Apple 服务例外无法按目标流量细分。
  • 节点重启、凭证轮换或代理故障后需要人工到场恢复。
  • 私有依赖、签名凭证和普通构建任务共用同一台不可隔离的设备。

这类场景下,JEXCLOUD 的远程 Mac 更适合被当作一台隔离验证节点或团队节点池成员,而不是用来替代所有本地设备。建议先用本文的四类流量地图和验收清单测试一台节点,只有代理接入、内部依赖、证书信任和无人值守恢复全部通过后,再决定是否扩展为团队规模的远程 Mac CI 容量。

JEXCLOUD

用 JEXCLOUD 快速搭建稳定的 Mac CI 节点

租用可远程访问的 Mac 环境,将代理、证书与凭证配置统一到 CI 服务账号的实际运行环境中。

JEXCLOUD 提供多地区 Mac 节点选择,方便你根据团队网络与依赖源访问需求部署构建任务。

立即租用