简体中文
  • pnpm
  • 安全
  • 依赖关系
  • npm
  • yarn

使用 PNPM 升级传递依赖关系:修复安全漏洞而不破坏系统

修复安全漏洞可能是一项令人沮丧的任务,尤其是当它涉及传递依赖关系时。了解如何在不影响直接依赖关系的情况下升级它们。

Gao
Gao
Founder

如今,安全漏洞在软件开发中是一个常见问题。幸运的是,我们有像 GitHub Dependabot 这样的工具,可以帮助我们通过自动检测和拉取请求使我们的依赖关系保持最新。

Dependabot

然而,事情并不总是如预期般顺利。由于某些依赖关系是传递性的,升级它们对于这些工具来说可能很困难,因为它们不知道更改的影响,以及在出现冲突时该如何决策。我们需要手动处理这些情况。

无效的方法

  • pnpm up 这样的官方命令会弄乱你的 pnpm-lock.yaml 文件。这方面有一个 问题,在撰写本文时仍然开放。
  • 安装具有目标传递依赖的直接依赖的最新版本可能不起作用。如果直接依赖没有升级版本定义,传递依赖将不会被升级,因为它已在 pnpm-lock.yaml 文件中解析并锁定。

解决方案

overrides 字段 是 PNPM 中的一项强大功能,允许你覆盖某些版本的解析。我们将使用此功能来升级传递依赖关系,并使更改尽可能最小化。

让我们使用上述的 Dependabot 警报作为示例。它告诉我们 follow-redirects 包有一个安全漏洞,并且已修补的版本是 1.15.6。然而,直接依赖 gatsby 使用了 axios,而 axios 依赖于 [email protected]

第一步:查找传递依赖关系

有很多方法可以定位传递依赖关系,但我推荐最直接的方法:搜索 pnpm-lock.yaml 文件。

“pnpm why” 如何?

pnpm why <package> 命令确实很有用。然而,在这种情况下它可能会让你困惑。例如,当我运行 pnpm why follow-redirects 时,以下是输出的一部分:

实际上,pnpm-lock.yaml 文件中 follow-redirects 只有一个解析。pnpm why 命令可能会向你显示依赖于同一版本包的多个路径。

第二步:添加覆盖

最简单的情况是在 pnpm-lock.yaml 文件中只有一个解析。你可以将覆盖直接添加到 package.json 文件中:

如果你在一个工作区中,你应该将覆盖添加到工作区的根 package.json 文件中。

第三步:应用更改

运行 pnpm install 以应用更改。我们可以看到 follow-redirects 包升级到 1.15.6,并且 pnpm-lock.yaml 文件的更改最小。

现在你可以从 package.json 文件中删除 overrides 字段以保持文件整洁。然后再次运行 pnpm install 以验证没有 overrides 字段时更改也可以应用。

故障排除

上述步骤是理想情况。事情不总是如预期般顺利。以下是一些故障排除提示:

移除 "overrides" 字段后版本恢复了

当依赖包具有固定版本或不包含目标版本的范围时,可能会发生这种情况。检查依赖包的 package.json 文件,在这种情况下是 axios,看看是否适用。

如果是这样,则需要将 overrides 字段保留在 package.json 文件中,直到依赖包升级版本定义。

对于传递依赖关系有多个解析

随着项目的增长,pnpm-lock.yaml 文件中可能会出现多个对同一包的解析。例如,可能有两个主要版本的相同包 foo

漏洞报告显示 [email protected] 存在安全问题,并在 1.0.1 中修复,而 [email protected] 不受影响。我们不能简单地添加一个覆盖到 foo

  • 如果我们添加覆盖 "foo": "^1.0.1",则 [email protected] 将被降级到 1.0.1。这可能会破坏项目,因为可能会在依赖包中使用 [email protected] 的某些新功能。
  • 如果我们添加覆盖 "foo": "^2.0.0",则 [email protected] 将会升级到 2.0.0。这可能会破坏项目,因为 [email protected] 可能有一些重大更改。

假设 foo 遵循语义版本控制,我们可以这样添加覆盖:

这将仅会将 [email protected] 升级到 1.0.1,并保持 [email protected] 不变。

结论

在 PNPM 直接支持升级传递依赖关系之前,overrides 字段是修复安全漏洞而不破坏系统的一个很好的解决方法。希望本文能帮你更有效地处理这些情况。在 Logto,我们使用这种方法来保持我们的依赖关系最新和安全。