结论:可信且稳定的工作负载,可以在权限边界和主机清理均有证据的前提下评估常驻 Runner;执行不可信代码或高权限任务,应优先评估一次性 Runner,并自动清理或重建承载环境。一次性注册只限制 Runner 接收任务的生命周期,不能证明底层 Mac 已恢复干净。
本周建议动作:先抽查一条外部贡献代码工作流和一条签名发布工作流,逐项核对触发条件、令牌权限、Keychain 使用、节点网络范围与任务后的清理记录;有一项无法验证,就先不要让两类任务复用同一台常驻 Mac。
负责自托管 Mac Runner 机群、需要决定节点按任务复用还是持续在线的 IT 负责人,适合阅读本文。
管理 iOS/macOS CI 安全边界的平台工程师,以及正在评估 Mac 构建资源的技术总监,也能用下面的验收步骤厘清责任。
GitHub Actions 自托管 Mac Runner 的生命周期不是主机隔离
选型先分清四个状态:任务结束、Runner 注销、主机清理、干净环境重建。它们不是同一件事。GitHub 的文档说明,启用一次性运行后,Runner 处理一个任务便会自动注销;注销后由企业自行安排清理 Runner 承载环境。换句话说,自动注销解决的是调度注册问题,不能替代对磁盘、用户目录、Keychain 或系统状态的验收。官方自托管 Runner 参考文档也要求将一次性 Runner 的日志转发至外部存储,以便在运行环境删除后仍能诊断。
| 决策维度 | 常驻 Runner | 一次性 Runner |
|---|---|---|
| 任务接收 | 节点持续注册并可接收后续任务 | 单个任务完成后自动注销 |
| 工作区与缓存 | 可能保留并被后续任务复用,需验证残留 | 仍需检查任务后主机如何清理或重建 |
| 凭证风险 | 后续任务可能碰到前一任务留下的状态 | 降低跨任务复用机会,但不自动擦除主机 |
| 工具链与环境 | 可保留已安装工具与缓存,需防止漂移 | 可通过重建环境验证基线,需维护重建流程 |
| 诊断证据 | 可从节点本地日志排查,但需设置留存 | 日志须在节点销毁前外传并验证可读 |
| 适用判断 | 可信、稳定、可审计且清理责任明确的任务 | 不可信或高权限任务,且主机清理机制可验证 |
一次性 Runner 常见设置方式如下。此命令只说明注册参数,不包含令牌,也不表示完成了主机清理:
./config.sh --url "$RUNNER_URL" \
--token "$RUNNER_TOKEN" \
--ephemeral
GitHub 文档说明,一次性 Runner 只接收一个任务,完成后自动从服务端注销;如需再次运行,承载环境的准备、擦除或重建仍由团队的自动化流程负责。
先按任务来源划分信任边界
仓库属于同一组织,并不意味着其中的每个工作流都可信。应以触发事件、被执行的代码来源、工作流修改权限和任务可获取的凭证为判断依据;特别检查外部贡献分支、由手动触发的工作流,以及能够检出并执行外部提交内容的任务。
例如,外部贡献者提交的代码可能经由构建脚本、依赖安装或测试命令在 Runner 上执行。审批流程可以限制任务是否启动,却不等于主机隔离;如果获批的工作流实际执行不可信代码,Runner 所在环境仍需按不可信任务评估。官方安全使用说明明确提醒,自托管 Runner 不保证运行在临时、干净的虚拟机中,不可信代码可能持续影响 Runner 环境。
| 任务类别 | 初始信任判断 | Runner 选择倾向 | 必须核对的条件 |
|---|---|---|---|
| 受保护分支的常规构建 | 相对可信,但仍须审查工作流与依赖 | 可评估常驻 | 代码审查、最小令牌权限、工具链变更记录 |
| 外部贡献代码的构建与测试 | 不可信输入 | 优先评估一次性 | 不向任务提供不必要的 Secrets;验证主机清理或重建 |
| 发布签名与部署 | 高权限、影响面大 | 使用隔离且受控的执行路径 | 签名材料访问范围、审批路径、Keychain 清理与审计 |
| 手动触发的临时任务 | 取决于触发者、参数和代码来源 | 按权限与代码来源决定 | 谁能触发、能否改变工作流、任务是否会执行外部内容 |
使用 pull_request_target 时尤其要审查工作流是否检出并执行外部贡献代码。官方说明指出,该事件在基础分支上下文中运行;不能因为工作流审批或分支归属,就把被执行的代码自动视为可信。安全使用 pull_request_target 的说明
凭证管理要覆盖任务结束之后
评估 Mac CI 环境隔离时,不要只问“本次工作流拿到了哪些 Secrets”,还要追踪它们进入主机后的去向。工作流显式注入的环境变量、临时文件、SSH 密钥、签名身份、Keychain 项,以及构建脚本可能访问的内网服务,都可能让任务影响超出单次执行。
GITHUB_TOKEN 会按工作流任务生成,并在任务结束时失效;但这不代表其他凭证也自动失效。仓库或组织 Secrets、签名材料及自行配置的访问令牌,仍应按其各自的有效期、访问权限和清理方式验证。官方令牌说明和Secrets 管理文档建议限制凭证权限,并明确哪些工作流可以使用它们。
环境 Secrets 的审批也不是主机安全边界。官方文档特别说明,自托管 Runner 上的工作流不会因使用环境而在隔离容器中运行;因此,不能把“设置了必需审查者”当成节点已隔离的证据。环境与部署保护规则说明
具体核查时,可要求每个高权限任务提供以下证据:
- 工作流的
permissions只开放实际需要的令牌权限,并能说明为什么需要写入权限。 - 签名任务使用的身份仅由指定任务访问;任务后检查 Keychain 和临时文件,不假设注销 Runner 会移除它们。
- Runner 网络只开放构建所需的仓库、依赖源和服务;不要因为任务属于组织就默认其可访问内网。
- 清理记录能显示工作区、凭证落点和主机状态的核验结果;无法确认清理完成时,停止节点复用。
第二步:把环境重建与日志留存纳入验收
常驻节点的便利在于保留工具链、依赖和缓存,但环境可能随手工更新、失败任务或残留文件逐渐偏离基线。一次性节点更容易把“每次如何得到环境”变成可审查流程,但若重建脚本没有覆盖 Xcode、依赖、模拟器状态和必要配置,也不能仅凭“重新创建”证明环境一致。
环境一致性应靠实际对照,而非推测构建速度。在试运行中记录工具链版本、依赖锁定状态、工作区清理结果与模拟器状态;同一工作负载分别检查常驻任务前后和重建后差异。没有测量记录时,不应承诺某种模式更快,也不应把缓存保留当作性能结论。
审计也要跟着生命周期设计。常驻 Runner 的本地 _diag 目录可提供 Runner 与任务诊断日志,但如果节点故障或被重置,日志可能一并丢失;一次性 Runner 同样需要在环境销毁前将日志转存到外部,并验证外部记录能关联到对应任务。官方监控文档说明,Runner 日志保存在安装目录的 _diag 文件夹,同时要求一次性 Runner 的日志在外部转发和保留。监控与故障排查文档
按证据完成验收,而不是只看 Runner 状态
以下步骤可用于现有 Mac Runner 试点,也适用于准备新增节点的评审。每一步都应保留配置或测试结果;如果某项无法验证,先把节点限定为已知可信的低权限工作负载。
第一步:列出触发源与执行内容。从工作流文件和仓库设置中,标出受保护分支、外部贡献、手动触发、发布任务及能执行外部代码的步骤。审查触发事件、检出 ref 和构建命令,不以仓库归属代替信任判断。
第二步:盘点任务可用凭证。逐项列出 GITHUB_TOKEN、仓库或环境 Secrets、签名身份、SSH 凭证和内网访问能力,记录任务是否确实需要这些权限。对签名材料,安排任务结束后的实际清理与再读取测试。
第三步:观察任务之间的残留。在隔离的测试流程中,检查工作区、缓存、临时文件、Keychain 和模拟器状态。可在任务中输出非敏感的环境标识或预设测试文件状态,用以确认后续任务能否读到前一任务留下的内容;不要把真实凭证写入日志。
第四步:验证清理或重建链路。确认自动化流程覆盖 Runner 注销之后的主机动作,并记录成功、失败与回退状态。若只能注销 Runner、无法确认主机内容已擦除,应按未完成隔离处理,禁止不可信任务与可信任务复用。
第五步:验证日志外传和故障调查。模拟一次失败任务,确认外部日志包含足以定位 Runner 与工作流任务的信息;再确认删除或重建承载环境后,调查人员仍能取得这些证据。若日志只能留在即将销毁的节点本地,先补齐外部留存再投入生产。
第六步:先小范围运行并设置回退条件。在常驻与一次性模式各选一类可信任务进行验收,比较基线偏差、残留检查、凭证范围与排障材料。只要出现清理不可证明、日志无法取回或权限超出任务需要,就回退到可信任务专用节点,暂停高风险任务接入。
用三个决策表确定运行模式
下表用于把运行模式与基础设施责任一起评审。一次性 Runner 的单任务属性有官方依据;表内关于组织如何安排主机清理、工具链重建和恢复责任,则是企业应自行验证的控制措施,不是 Runner 自动提供的保证。
| 评审指标 | 可评估常驻 Runner | 优先评估一次性 Runner | 不满足时的处理 |
|---|---|---|---|
| 任务信任 | 受保护分支、代码来源和依赖均受控 | 外部代码或信任程度不确定 | 不把任务放入共享常驻节点 |
| 清理能力 | 有可执行的任务间清理及检查记录 | 可自动销毁或重建承载环境 | 不能证明干净时,不认定隔离完成 |
| 凭证边界 | 仅可信任务可访问限定凭证 | 凭证使用短时、范围最小且可撤销 | 拆分签名任务与普通构建任务 |
| 工具链一致性 | 版本与缓存变化可追踪 | 环境可按基线重建并验收 | 暂停扩大任务范围,先建立基线 |
| 审计与恢复 | 节点本地日志有备份,责任人明确 | 节点销毁前日志已外传 | 无法调查失败任务时,不进入生产 |
| 运维责任 | 有人负责更新、清理、故障恢复 | 有人维护创建、销毁与重建自动化 | 明确责任人和回退路径后再选型 |
| 验收对象 | 应保留的证据 | 通过条件 |
|---|---|---|
| 工作流信任 | 触发条件、代码来源、仓库权限 | 能区分可信发布与不可信贡献代码 |
| 凭证暴露 | permissions、Secrets 范围、Keychain 检查记录 |
后续任务不能读取前序任务遗留凭证 |
| 主机清理 | 注销记录、擦除或重建结果、残留检查 | 有可复核的主机状态证据,而非只有 Runner 离线状态 |
| 环境一致性 | Xcode、依赖、工作区与模拟器检查结果 | 版本及状态符合团队维护的基线 |
| 故障诊断 | 外部 Runner 日志、任务日志与关联信息 | 承载环境删除后仍能还原故障经过 |
GitHub 也提供从组织或仓库移除 Runner 的操作说明,但从服务端移除注册记录与擦除 Mac 上的数据仍是不同动作;验收时应分别核对服务端记录和主机处理结果。移除自托管 Runner 的说明
⚠️ 一次性 Runner 只表示它在完成单个任务后不再继续接收任务。若没有主机销毁、重置或干净环境重建的可验证记录,就不能据此宣称 Mac CI 环境已隔离。
常见问题
外部贡献代码可以放进组织级常驻 Runner 吗?
不应只因 Runner 属于组织或仓库,就视为外部贡献代码可信。先确认触发条件、实际执行的代码以及该任务可用的令牌、Secrets 和网络资源。若任务会执行不可信代码,优先评估一次性承载,并验证主机清理或重建;若清理无法证明,就不要让它与发布任务共用节点。
Runner 注销后,怎么确认 Mac 已经干净?
注销记录只能证明 Runner 不再以原注册身份接收任务,不能单独证明主机状态。需要查看任务结束后的清理记录,并抽查工作区、临时凭证、Keychain、模拟器状态和网络访问配置。若没有可审计的重置结果,按环境仍可能残留处理,选择销毁并重建,或停止节点复用。
审批和 Runner 分组能不能替代 Mac CI 环境隔离?
不能。审批用于约束任务是否获准继续,分组用于安排 Runner 的可用范围;它们都不等同于磁盘、用户目录或系统状态隔离。评估时应分别测试主机之间的访问边界、任务后的凭证清理和日志外传。只有这些主机层证据齐备,才能把隔离作为实际控制措施。
一次性 Runner 需要保留哪些排障材料?
至少要让 Runner 日志与具体工作流任务可以关联,并在节点销毁之前完成外部转存;此外,还应按企业审计要求保存工作流日志、环境版本和清理结果。演练时先删除或重建测试节点,再由未登录该节点的排障人员调取材料,确认失败原因仍可调查。
结尾建议:先核对 Mac 的交付与清理责任
常驻方案的主要代价,是需要持续治理节点更新、工作区残留、凭证回收和工具链漂移;一次性方案则增加创建、日志外传、主机清理与重建失败恢复等运维责任。两者都不是免运维方案,关键是团队能否拿出任务权限、清理结果和故障证据。
若团队需要临时或按周期增加真实 Mac 构建环境,可先查看远程 Mac 方案与交付选项,再从NodeMini 服务入口核对实际访问方式、环境重置责任和限制。只有这些条件能被书面确认并纳入验收,才适合评估租赁;若要求长期固定高负载、必须直接控制物理接口,或清理责任无法确认,则应优先评估自购设备或团队可直接管理的其他基础设施。