本文面向开源维护者、iOS 安全负责人和 Runner 平台工程师,说明不可信 PR 为什么不能直接进入持有凭据或残留状态的长期 Mac Runner。文中用方案对比、通过/不通过清单和故障分流条件,帮助核验仓库访问、凭据边界、任务清理与节点恢复。
结论:不要让来源不可信的外部 PR 直接运行在持有敏感凭据或残留状态的长期自管理 Mac Runner 上。只有在 Runner 访问范围受限、测试与签名发布分离,并且任务后清理经过真实验证时,才考虑让它运行不可信代码;否则应把 PR 测试分流到隔离环境。
适合开源项目维护者:判断外部贡献工作流能否接触自管理 Runner。 适合 iOS 团队安全负责人:隔离测试构建与签名发布任务。 适合平台工程师:核对 Runner 组、节点清理和审计责任。
GitHub Actions Mac Runner 外部 PR 隔离先看工作流来源
工作流执行的代码不一定来自受信任分支。外部贡献者提交 PR 时,工作流可能处理 PR 分支或合并结果中的代码;构建脚本、依赖安装脚本、测试配置都可能执行贡献者提供的内容。自管理 Runner 与 GitHub 托管的临时干净虚拟机不同,GitHub 明确提醒:不可信工作流代码可能持续影响自管理 Runner 环境。公开仓库尤其要谨慎,不能因为 PR 触发器有默认保护,就把本地节点视为隔离沙箱。可对照官方自管理 Runner 安全用法说明和工作流触发事件说明。
外部 PR 能不能用自管理 Mac Runner? 判断标准不是“能否排进队列”,而是“执行后能否接触其他任务、凭据和内部资源”。公开仓库的外部 PR,优先使用与私有网络、签名材料和长期节点状态隔开的运行环境。若当前 Mac Runner 具有共享工作目录、登录钥匙串、发布证书或内网访问能力,就应判为不通过,先分流再继续。
还要分清触发器差别。来自 fork 的 pull_request 工作流通常只能拿到只读权限的 GITHUB_TOKEN,其他仓库密钥不会传入该工作流;但这不等于自管理主机被隔离,也不代表后续步骤没有机会触碰节点上的本地文件或进程。GitHub 的密钥使用说明解释了 fork 工作流的密钥边界。pull_request_target 则运行在基础仓库的信任上下文中,可能拥有仓库密钥和更高权限;若再检出并执行 PR 代码,风险会明显升高。不要把它当作“安全地运行外部代码”的替代开关,具体边界见官方专门说明。
Runner 组与标签的权限边界
Runner 标签用于匹配任务所需的运行环境,不是权限控制。工作流里写了 runs-on: [self-hosted, macOS],只说明任务按标签路由;不能证明只有可信仓库或可信工作流有资格使用这台机器。
组织级 Runner 组才是访问策略的一部分。核查时要确认组允许访问的仓库是明确的选择集,而不是组织内所有仓库;如果平台支持工作流级访问限制,也应收窄到指定工作流,并检查分支或提交版本约束。Runner 组访问文档说明组织可以按仓库设置访问策略;Runner 组概念说明则将其定位为管理和限制 Runner 访问的边界。注意:Runner 组不是对主机状态的清理机制,也不会自动判断 PR 代码是否可信。
| 方案 | PR 任务的权限边界 | 复用状态风险 | 本篇风险评分 |
|---|---|---|---|
| 托管的隔离 Runner | 不与自管理 Mac 主机共享本地状态;仍需限制令牌和密钥 | 较低,但仍要审查工作流 | 低 |
| 长期自管理 Mac Runner | 取决于仓库、工作流和主机权限配置 | 高;工作区、进程或本地凭据可能残留 | 高 |
| 每个任务后重建或清理的隔离 Mac 节点 | 需另行配置访问范围、凭据和恢复流程 | 可降低跨任务残留风险,不能替代权限控制 | 中 |
表中评分是基于本文验收条件的定性判断,不是 GitHub 的官方评级,也不构成安全认证。真正的仓库访问限制要在 Runner 组策略中核验,不能只看工作流 YAML;标签匹配正确但组策略开放过宽,仍判不通过。
怎样收窄 Runner 组的仓库访问范围? 在组织设置中检查每个 Runner 组的仓库访问范围,逐项确认获准仓库;再检查工作流访问策略和 Runner 注册层级。新 Runner 若未指定组,可能落入默认组,所以验收不能只检查自定义组。把有外部 PR 的公共仓库与含签名材料的发布仓库分开管理,避免同一 Runner 组横跨两类工作负载。
凭据与 macOS CI 权限分离
不要把“日志里没看到密钥”当作凭据安全证据。恶意脚本可以尝试从环境变量、钥匙串、配置文件、缓存或网络连接中读取凭据,也可能利用当前工作流令牌执行超出预期的操作。检查应覆盖签名证书、发布密钥、私有制品库令牌、SSH 凭据,以及 Runner 账号可访问的其他目录。
iOS 测试与签名发布应拆成不同任务和信任边界:外部 PR 仅运行不需要发布凭据的检查;签名与发布只由受信任分支或经过审批的发布工作流执行。将 GITHUB_TOKEN 权限设为任务所需的最小集合,并在具体工作流中显式声明权限。仓库设置支持限制默认令牌权限,验收时要核对仓库当前配置和工作流中的权限声明。
Mac Runner 上的签名凭据怎样与 PR 测试隔离? 先确认 PR 工作流无法读取发布密钥,也不能访问装有证书的钥匙串或签名文件;再确认 PR 任务的令牌没有写入、发布或审批权限。若自管理节点必须保留签名凭据以供发布使用,就不要把外部贡献任务调度到该节点。仅在工作流中省略密钥引用,不足以隔离主机上已有的本地凭据。
任务结束后的清理与节点恢复
长期节点的隐性成本不只是磁盘占用。工作目录可能保存上次构建产物和配置;后台进程可能继续运行;缓存、临时文件、用户级钥匙串和日志中可能留下敏感内容。一次任务成功结束,不代表这些状态已被清除。
GitHub 提供 Runner 作业开始或结束时调用脚本的机制,可用于环境准备、目录清理或遥测;但脚本是否覆盖实际残留,仍需由维护方测试。官方前后置脚本说明提到相关脚本可用于清理目录等任务。另一种做法是使用一次性 Runner:官方文档说明,临时 Runner 处理最多一个作业后会自动注销;复用底层硬件时仍须自动化重建干净环境,并将日志转存到外部存储。
⚠️ 一次性注册不等于一次性硬件。若任务结束后只是注销 Runner,而磁盘、用户目录、后台进程或钥匙串仍保留,下一次任务仍可能继承旧状态。
按以下步骤验收,不要只读 YAML:
- 标记来源。 列出触发器、来源分支、是否允许 fork PR,以及工作流实际检出并执行的代码。发现外部代码会进入持有敏感信息的长期 Runner,即判不通过。
- 检查访问范围。 在组织设置中逐一核对 Runner 组的获准仓库和工作流;对照每个工作流的
runs-on。标签匹配正确但组策略开放过宽,仍判不通过。 - 盘点凭据与权限。 查看令牌权限、仓库和组织密钥、签名材料、钥匙串及内网访问。用非敏感测试验证 PR 作业无法读取发布凭据;不能以日志未显示密钥作为通过依据。
- 执行清理测试。 在无敏感数据的测试工作流中写入专用标记文件、启动可识别的后台测试进程,再让任务结束。检查工作目录、缓存、临时目录、进程和相关用户状态是否按策略清除。
- 验证复用前状态。 再运行一个无关的后续任务,确认它看不到前一任务的标记文件、进程或测试凭据。若清理失败,先停止节点接收任务,再恢复或重建环境。
- 保留记录并复核。 保存工作流运行记录、Runner 日志、清理结果、节点恢复时间和责任人。单次测试通过只能证明当次结果,不能保证后续脚本、镜像或权限变更后仍然安全。
通过条件与失败分流
外部 PR 执行结束后要检查什么? 检查工作区和临时目录、缓存、后台进程、钥匙串与凭据文件、Runner 在线状态,以及日志是否包含不该出现的敏感信息。若节点曾经接触凭据,清理失败时应将其隔离,按团队流程轮换可能暴露的密钥,并在重新接收可信任务前复核环境。
使用下面的条件分支决定任务去向:
- ✅ 若工作流来源明确、Runner 组只开放给必要仓库、PR 无权读取签名或发布凭据,且清理测试通过:可按既定策略运行,并持续保留审计记录。
- ⚠️ 若访问范围已收窄,但节点是否干净尚未通过真实任务验证:不要接收外部 PR;先在隔离环境完成测试,再验证清理与节点恢复。
- ❌ 若公开仓库外部 PR 能调度到持有凭据的长期 Mac Runner,或任务后仍有残留:立即阻断该路由,停止复用节点,并将未信任任务改走隔离环境。
- ❌ 若使用
pull_request_target,同时检出并执行外部 PR 代码:按高风险配置处理,先拆分工作流或移除不可信代码执行,再恢复任务。
先按这份清单检查现有 Runner 的仓库访问、凭据边界和任务后清理;如果自购 Mac 节点需要长期维护、系统更新和清理自动化,成本未必适合短期测试或临时构建。远程 Mac 也不是天然隔离方案,仍要逐项核实交付方式、节点复用状态与权限边界。需要了解远程 Mac 的基本使用与运维事项时,可先看Mac 使用帮助。若只需要临时构建环境,也可以把ZekVPS 的 Mac 服务入口作为方案比较起点;在把外部 PR 接入之前,先确认具体节点能力,再决定是否适用。
为外部 PR 配置独立的 Mac 构建环境
使用 ZekVPS 裸金属 Mac,让不可信构建与持有凭据或长期运行的节点分开。
每台 Mac mini 独享完整 macOS 与管理员权限,可按仓库或任务规划环境边界。
若你正准备把 MCP 或 Agent 从 Demo 推到日常运转,先固定一台可快照的云 Mac 节点往往比换第五个框架更有效。 查看 ZekVPS 云端 Mac mini 套餐 — 把实验环境和生产桌面拆开,部署会踏实很多。