RFC-0119:系统绝对路径被视为有害

RFC-0119:系统绝对路径被视为有害路径
状态已接受
领域
  • 构建
说明

制定策略,以尽可能在任何位置使用相对路径。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2021-06-20
审核日期(年-月-日)2021-07-28

摘要

  1. 制定一个优先考虑相对路径或源绝对路径的政策 多个枚举实例中的系统绝对路径,旨在 应用场景。
  2. 继续以自动化方式执行此政策,造成回归问题 停止。
  3. 清理之前使用的系统绝对路径。

背景

熟悉相应主题的读者可以跳过

路径

定义

读者应熟悉 paths

下面,我们将使用以下定义:

  • 系统绝对路径:位于本地文件系统根位置的路径。通常用 / 前缀。
  • 来源绝对路径或项目绝对路径:相对于某个资源的根目录的路径 源代码树或项目检出。通常用 // 前缀表示。
  • CWD 相对路径:相对于当前工作目录的路径。

在下文中,我们将系统绝对路径称为绝对路径,从而进行泛化; 视为相对路径,因为它们以相对于 另一个路径。

Fuchsia 构建系统中的路径

在构建系统中使用路径来指代操作的输入和输出文件。 Fuchsia 构建系统使用 GN 定义其 build 图表。根据既定的最佳实践, 表示 GN 中的路径相对于另一个根目录(如 构建根目录或源代码根目录中

生成的代码中的路径

代码可能会出于各种原因引用路径。检查的源代码 中的 无法引用绝对路径,因为它们不可移植, 在提交队列 (CQ) 机器上有意义,会被拒绝, 那么同样的绝对路径对于其他工程师来说毫无意义 同样的内容。不过, 特定计算机,并且未签入可能包含绝对路径, 运行(成功构建和/或运行)。

Fuchsia 利用多种工具来生成源代码。例如 FIDL 使用了 fidlc,而 Banjo 使用了类似的工具。

设计初衷

在 编译系统、工具调用、生成的源代码以及其他 工件

可移植的工件

如上所述,相对路径是可移植的,因为它们是相对于 双方可以商定的参考点,如紫红色的根 source checkout 或 build 输出目录的根目录。在很多情况下 这样不仅可移植路径具有可移植性,而且还是一项硬性要求。

用于分布式构建的可移植工件

分发构建操作是指将输入发送到构建操作的行为, 例如将 C/C++ 文件编译到对象文件中, 执行。远程服务器可以代表客户端执行操作, 返回结果。通常,远程服务器依赖于基于内容的 缓存来完全跳过该操作。

分发构建操作有很多好处,但这超出了本课程的范畴 文档。

由于客户端和服务器可能不会就绝对路径达成一致,因此相对路径 在指定要分发的调用详情时 以及任何已上传的制品的内容中,因为它们相互引用。 对于依赖于缓存、 其中,调用详细信息用作缓存键的一部分。即使 绝对路径,但使用它们可能会使缓存机制失效, 客户端可以检出相同的源代码,然后将请求发送到 和绝对路径不同的服务器。

如果构建路径或生成的代码中存在绝对路径, 之前就存在的一些问题例如,Fucsia 开发者可以使用 Goma 用于分发 C/C++ 构建操作。的 Fuchsia 用户 在引入采用绝对值规范的变更之前,Goma 曾出现过服务中断的情况 通过 C/C++ 包含目录的路径。在某些情况下是分布式 build 会失败并强制进行本地回退,这样速度会变慢。在其他情况下 分布式构建会成功,但无法命中缓存,从而导致 大幅增加后端负载,导致级联故障。

分发构建操作时的另一种类似的故障模式是绝对路径 。我们之前发现, 在分配操作之前检查是否存在此类路径,并以 构建操作失败的警告和有用的错误。

其他实例中,绝对路径导致 build 正确性 问题。

用于流水线的可移植工件

在分配操作时,有时需要一个远程渠道 用于执行不同的任务。例如,某些机器可能更适合 以及更适合运行已构建的测试的其他测试。 有时,操作会表现为一个分支和联接的图表,例如 构建一套测试,然后分叉到多台机器,每台机器运行一个 测试分片,然后联接结果。

在前面的案例中,路径在客户端与服务器之间交换, 在这种情况下,路径在流水线中的不同服务器之间交换。通过 尽管交换的性质不同,但对于 Responsible AI 而言, 原因都一样

绝对路径可能会导致流水线中断。例如,流水线 可产生测试覆盖率的算法在过去因覆盖率提升而中断 在较早阶段生成的报表包含指向 之后在运行其他服务器时 是覆盖率报告制作流水线的阶段生成 覆盖率映射文件使用的是绝对路径,我们对此进行了更改 将路径相对于给定底基。

使用其他形式的代码时也会出现类似的中断问题 插桩 - 绝对路径曾用于调试信息文件、 用于解析相对于源代码行的 PC 偏移量的记录。

用于缓存的可移植工件

可以缓存构建输出以加快后续构建的速度,这称为 增量构建。此类缓存通常保存在本地 或构建服务器的特定实例上使用。理论构建 可以在不同的构建工作器(工作站和 只要网络容量足以支持此任务,并且 没有安全和隐私问题。

Fuchsia 目前不会在不同机器之间重复使用构建缓存, 众所周知,某些构建输出包含绝对工件。取而代之的是,Fuchsia 开发者和 Fuchsia 分布式构建器最多会使用自己的本地化 先前运行的构建中的缓存。这是一个重大损失 优化和提高工程效率。

可重现的制品

如果在工件中使用绝对路径,会导致我们无法实现可重现的 build

目前,可重现的 build 并不是 Fuchsia 的既定目标。然而, 考虑可重现构建的优势, 知道这是将来需要的媒体资源,并且使用 工件中的绝对路径会妨碍我们实现可重现性。

另请注意,还有一些其他原因会导致工件不可重现,大多数 这些时间戳超出了此 RFC 的范围。

工作量极少

Fuchsia 目前通过生成完整的系统映像并在设备上运行测试, 为设备铺路。将来,我们可能希望加快这一过程,例如 例如,通过推送到测试设备,仅将自上次 。要测试的大多数更改只会影响 因此该方法的这一操作 使测试设备的启动速度明显加快。

如果绝对路径泄露到工件中,可能会有更多 blob 失效 要测试的不同更改之间有何区别。

树外 Fuchsia build

在上文中,我们介绍了 Fuchsia 由于绝对 以及绝对路径使 Fuchsia 难以 不断发展和改进。利用绝对路径解决问题的紧迫性 依据历史背景进行衡量。例如,以前 Fuchsia 并不 利用增量构建或缓存 但他们都学会了容忍缺陷,这使得 Fuchsia 无法采用 增量构建和缓存。

如果 Fuchsia 成功,其他项目将消耗代码和工件 并面向 Fuchsia 开发应用。可以肯定的是,至少 这些项目将需要一个更易用的构建规则和工具系统, 可以满足与 Fuchsia 项目不同的需求。例如, 的这些客户的运营规模可能已经达到 必不可少 缓存。如果 Fuchsia 为实现目标提供了障碍 那么 Fuchsia 开发者和其他客户将面临障碍 采用率。

分布式信任

如果 build 的所有工件都可以重现,那么这打开了一扇新的大门 属性。例如,可重现 build可以作为 一种用于验证分布式计算系统完整性的加密信任链, 二进制文件不可信的一方可以审核这些二进制文件,方法为 使用相同的源代码和构建系统重现它们。无法重现 二进制文件可能是恶意篡改的证据。

如果工件中使用了绝对路径,则永远不会 能够重现相同的结果。

便利性

进行问题排查时,相对路径更易于使用。更常见的是 例如,比较不同位置之间的路径, 成功的操作和失败的操作 并找出任何有意义的 差异。

如果严格在本地工作,绝对路径会非常方便。对于 例如,可以从工具调用中复制绝对路径,并在 并保证能够正常运行,因为它不适用于 对当前工作目录敏感的实例。此外,任何两条路径 是绝对标准化的(例如,... 部分已解析, 链接等),可以通过字符串标识来检查是否等效。 由于任何路径都可以设为绝对路径和标准化路径, 转换具有幂等性,因此可以对路径进行简单的等价检查 本地环境中的可用资源不过,没有任何限制 对绝对路径执行这种转换更为方便, 但由于这种从相对于绝对和/或标准化形式的转换 具有破坏性,无法在其他方向执行。因此, 更加包容所有用例,更倾向于使用相对形式。

设计

政策

我们会将载述的 GN 最佳做法推广为 常规政策,并将其应用于 BUILD.gn 文件的更广泛的应用。 具体而言,我们将提供以下建议:

  1. 构建系统作为命令行参数传递给工具的路径 应相对于调用该工具的当前工作目录 (如果是 GN/Ninja,则表示为 root_build_dir)。
  2. 构建时生成的文件中的路径应相对于同一根目录 build 目录中。例如:生成的源代码、软件包清单 depfiles.
  3. 运行时生成的路径应相对于项目源代码 根。例如:崩溃中的文件信息、测试覆盖率报告。

违规处置

我们将引入新工具,以净化 Fuchsia 版本的存在 工具调用和工件中绝对路径的图示。这些工具将 在 CQ 中进行了练习,以防止回归。

清理

上述工具将提供许可名单 并列出所有现有违规情况。清理工作将 以将许可名单的大小缩减为零。回归模型不会 在正常情况下可以列入许可名单。

实现

关于违规处置工具如何运作的实现细节不多 到 RFC 级别。不过,我们在下面提供了一些思路草案 让好奇的读者受益

正在清理 Ninja 文件

运行 GN 会生成描述 build 图的 build.ninja 文件。通过 此图表的说明包含所有工具调用,包括 要调用的工具以及作为参数传递给这些工具的路径。 使用的其他文件在 depfile 中引用。

可以使用 strings 处理这些文件,生成随后可被 已针对呈现为绝对路径而进行了过滤。这个简单的扫描程序 例如作为可在所有 build 下运行的主机测试 变体。

清理 build 引用的文件

除了对 Ninja 文件进行标记化和清理之外, 指定为构建操作的输入或输出文件。我们能够 从 Ninja 图或依赖项文件发现所有此类文件,假设 build 是封闭的。

检查是否存在为绝对路径的字符串

我们可以扫描 build 输出目录 (out/) 下的所有文件,生成 字符串并检查是否存在是绝对路径,则发出错误。它不是 而是一种额外的简单防护。

拒绝操作跟踪器中的绝对路径

我们已经有一款封装 GN 操作的工具, 可用于拒绝 depfiles 中的绝对路径。我们可以进一步 机制。

请注意,我们目前只使用操作跟踪器来封装自定义操作, 使所有构建操作成为一个子集。我们对相同的性能进行了 问题。从这个角度来看, 继续追踪行动并不是一项可靠而全面的策略。

使绝对路径失效

一种简单的方法,可确保结账流程中的所有相对路径都能正常运行 使绝对路径完全失效的次序是生成 Ninja,然后 将 checkout 目录移至其他位置(或直接重命名),然后进行 build。

$ fx gen
$ mv $FUCHSIA_DIR ${FUCHSIA_DIR}_renamed
$ fx build

如果任何构建调用将检出下的路径引用为绝对路径,则 构建将失败

此方法非常易于实现、可移植,并且性能不佳 开销。这样做的缺点包括 会让没有经验的人感到困惑,而且仍然有可能泄露 生成的工件中的绝对路径(例如 depfiles、srcgen、debug 信息)。

对运行时环境的更改

另一种方法是在 绝对路径会变为无效或无害。对于 例如,某些项目使用 chroot,以在结账根目录下构建沙盒。其他 构建系统会使用特殊的 文件系统来实现沙盒。

运行时方法值得考虑,因为它们可以提高正确性 保证。但效果提升 问题和具有挑战性 可移植性 问题

安全注意事项

路径可以用在解释相应路径(内容 则可能会影响敏感的系统行为。对于 实例、可作为可执行文件到内存中的文件的许可名单 页面。

在这种情况下,最好使用项目相对路径而不是实例路径 这些标记是相对于包含指定列表的目录的 或路径是相对于处理此列表的工具的 CWD 的路径。这个 是因为在 项目定义路径,而其他形式的相对路径可以是 根据全局可变状态(例如 CWD)进行不同的解释。

隐私注意事项

绝对路径偶尔会泄露个人身份信息。对于 例如,某人的用户名通常作为绝对路径的一部分 包含该人员的 checkout 或 build 输出目录中的文件。正在替换 使用来源相对路径的绝对路径可以避免 PII 的排空。

测试

在上文中,我们探讨了实现可捕获对“绝对值”字符的 路径。由于这些检查是作为构建步骤或主机测试实现的,因此它们 可以在 CQ 中运行,并作为持续测试运行。

确保不使用绝对路径的另一种方法是 无法容忍工程工作流的一个关键方面。例如,如果 绝对路径会中断某个分布式操作, 作为 CQ 的一部分,则开发者无法再引入破坏。

文档

当强制规定路径并非绝对失败的工具时,它们应产生 错误,链接到相应的问题排查页面。如果您能 操作跟踪程序,它会强制要求构建操作 封闭构建失败,则生成一条错误消息,其中包含指向封闭 build 的链接 操作页面。

缺点、替代方案和未知问题

在分布式构建空间中,我们不能执行任何操作, 可再现性领域。

我们可以制定一项政策,但不会执行它。可能的结果是 无法在分布式构建或 可重现性。

我们可以在此问题上做出改变,但代价是 和熵衰减的性质。

先验技术和参考资料

一位伟大的绝地武士曾经说过:“只有西斯人交易绝对。”