在 Chocolatey 下因签名或密钥错误而失败的 OpenVPN 安装,通常不是下载问题。软件包会运行一个验证步骤,调用 gpg,而 Windows 通过 PATH 解析这个裸名称。如果 Git for Windows 先安装,它自带的 gpg.exe 会排在 OpenVPN 期望的 GnuPG 构建之前,于是响应该调用的是错误的程序。你看到的错误就是那个程序决定抱怨的内容,所以它从不提及真正的原因。

PATH 的顺序决定运行哪个 gpg

Windows 没有可执行名称的中央注册表。当进程请求不带完整路径的 gpg 时,加载器按顺序遍历 PATH 中的条目并运行第一个匹配项。Git for Windows 在其 usr/bin 目录内附带一个最小的 GnuPG 构建,以便签名提交正常工作,而它的安装程序通常把该目录放在用户 PATH 的前部附近。

GnuPG 安装在自己的目录中,通常是 C:\Program Files (x86)\GNU\GnuPG\pub,该条目可能在列表靠后,或完全不在用户的 PATH 中。两个程序共享一个名称和大部分命令行接口,但不共享状态:Git 的构建在别处查找密钥环,可能是不同版本,也可能不接受安装程序传入的选项。这种不一致表现为签名或密钥错误,而这正是对错误二进制所见内容的如实报告。消息中没有任何内容指向加载器,因为加载器完全照做了被要求的事。

为什么你启动的 shell 决定结果

继承规则是值得内化的部分。子进程获得启动它的 shell 的环境,因此重要的顺序是 Chocolatey 启动那一刻的顺序,而不是你修复之后的顺序。

这就是为什么在设置窗口中编辑 PATH 并在同一终端重新运行安装往往毫无变化:终端保留了旧环境。任何修改之后都要启动新的 shell,并在再次尝试前在那个新 shell 中用 where.exe gpg 确认。这也是计算机级条目可能胜过用户级更改的原因:某些安装程序会加到机器 PATH 的开头,而机器条目先于用户条目被求值。如果两个级别都包含 GnuPG 路径,请决定你实际维护的是哪一个。

修复一:调整条目顺序

精确的修复是让预期的 GnuPG 目录胜出。打开用户的环境变量,编辑 Path,把 GnuPG 的 pub 目录移到 Git 条目之上。然后打开新的 PowerShell 窗口,因为正在运行的窗口仍持有旧列表。

另一种办法是为安装准备一个临时的干净环境:移除 Git 条目,打开新 shell,运行 choco install openvpn,然后再恢复它们。

两种方法奏效的原因相同,而第二种只有在你真正恢复条目时才安全。Git 的 usr/bin 从 PATH 中移除会永久破坏签名提交,下一个期望可用 gpg 的工具会以自己的消息失败,与 OpenVPN 毫无关系。如果你走临时路线,请把 Path 的原始值留在工单里,使恢复成为粘贴而不是重建。排序才是持久的修复;删除只是有期限的权宜之计。

验证,然后放回去

在 Chocolatey 将使用的同一用户上下文中前后验证。where.exe gpg 按解析顺序列出每个匹配项,所以第一行就是将要运行的那个;Get-Command gpg -All 在 PowerShell 中给出同样答案但更详细。然后 gpg --version 确认是哪个构建作出了响应。

如果 where.exe 仍把 Git 的副本列在首位,说明重排没有到达该会话,再多次重装也无济于事。分别检查机器和用户的 PATH(用 [Environment]::GetEnvironmentVariable('Path','Machine'))以及带 'User' 的同一调用,因为有效列表由两者组成。安装成功后,用 openvpn --version 再次检查,并启动一次服务或 GUI,因为软件包可能安装干净却留下无法启动的服务。

如果顺序正确的 PATH 仍失败,剩下的变量是软件包版本。被固定的 Chocolatey 软件包可能期望某个你的机器没有的 GnuPG 构建或安装路径。

先读软件包自己的日志,再改动其他任何东西。C:\ProgramData\chocolatey\logs\chocolatey.log 记录了失败的命令行以及运行它的目录,这能告诉你失败的调用是签名检查、解包还是安装后脚本。这个区别决定你是否还在调试 gpg。

防止重演的习惯是把 PATH 当作有文档化顺序的共享状态,而不是一袋目录。安装带有常见二进制名称的工具时,检查它在你打开的下一个 shell 中遮蔽了什么。然后写下你确定的顺序,因为下一个安装程序会追加,而下一个人会纳闷为什么在一台什么都没变的机器上签名检查会失败。安装前的一次 where.exe 能省掉整个循环。

相关文章