3.2 使用包注册表
9 分钟阅读
原文链接: https://docs.swift.org/latest/documentation/packagemanagerdocs/usingswiftpackageregistry/
3.2 使用包注册表
为 Swift Package Manager 配置并使用包注册表。
概述
Swift Package Manager 支持从任何实现了 SE-0292 以及相应服务规范的包注册表下载依赖。
在注册表中,包通过形如 scope.package-name 的包标识符来标识。
配置注册表
在 Swift Package Manager 中可以在两个层级配置注册表:
- 项目级:注册表将用于该项目内的包。设置保存在
.swiftpm/configuration/registries.json。 - 用户级:注册表将用于该用户的所有项目。设置保存在
~/.swiftpm/configuration/registries.json。
你可以用 swift package-registry set 子命令来指定注册表 URL:
| |
上面这条命令在项目级把注册表设置为 https://packages.example.com。传入 --global 选项可以把注册表设置在用户级:
| |
最终生成的 registries.json 大致如下:
| |
JSON 键 [default] 表示 https://packages.example.com 这个注册表是「无边界的」,当某个作用域没有找到对应的注册表关联时就会使用它。
在这个例子中,https://packages.example.com 会应用到所有作用域。
添加注册表包依赖
注册表包依赖通过包标识符在 Package.swift 中声明。例如:
| |
包管理器会查询该包作用域所映射的注册表,以解析并下载合适的发布版本。
注册表认证
如果注册表需要认证,可以用 SE-0378 引入的 swift package-registry login 子命令来配置。
目前支持基本认证和令牌认证。
你可以通过设置相应选项(即用户名/密码之一,或者访问令牌)来提供凭据,也可以在提示时输入:
| |
包管理器会把凭据保存到操作系统的凭据存储(例如 macOS 的钥匙串)或 netrc 文件(默认位于 ~/.netrc),并在发起注册表 API 请求时自动应用它们。
使用注册表解析依赖
解析注册表依赖包括以下步骤:
- 调用列出包的发布版本 API,获取某个包可用的各个版本。
- 通过获取某个包发布的清单文件计算依赖图。
- 确定要使用的包版本。
关于解析依赖的更多信息,参见解析与更新依赖。
为源代码管理依赖使用注册表
下面是一个源代码管理依赖的例子:
| |
注册表也可以用于源代码管理依赖。当依赖图是「混合」的(即同时包含源代码管理依赖和注册表依赖)时,这一点尤其有用。包管理器把来源不同的包视为不同的包,因此如果某个包同时以注册表依赖(例如 mona.LinkedList)和源代码管理依赖(例如 https://github.com/mona/LinkedList)的形式被引用,即使它们其实是同一个包,也会被视为不同的包,从而产生符号冲突。
Swift Package Manager 可以通过在源代码管理 URL 上做查找(例如 https://github.com/mona/LinkedList),看它是否与某个包标识符(例如 mona.LinkedList)相关联,从而对包去重。
你可以通过设置下列标志之一,来控制包管理器是否以及如何把注册表与源代码管理依赖结合使用:
--disable-scm-to-registry-transformation(默认):Swift Package Manager 不会把源代码管理依赖转换为注册表依赖。源代码管理依赖会从其对应 URL 下载;注册表依赖则会使用已配置的注册表(如果有)来解析和下载。--use-registry-identity-for-scm:Swift Package Manager 会在注册表中查找源代码管理依赖,并尽可能使用它们的注册表标识,以帮助在两种来源之间对包去重。换句话说,假设mona.LinkedList是https://github.com/mona/LinkedList的包标识符,那么包管理器会把依赖图中的这两个引用视为同一个包。--replace-scm-with-registry:Swift Package Manager 会在注册表中查找源代码管理依赖,并尽可能改用注册表来获取它们,而不是用源代码管理。换句话说,包管理器会先尝试从注册表下载源代码管理依赖,如果注册表中找不到该依赖,再回退到克隆源仓库。
从注册表下载依赖
注册表依赖解析完成之后,Swift Package Manager 可以从注册表下载所确定的包版本的源代码归档。
包的安全性
作为一项安全特性,Swift Package Manager 会对下载到的源代码归档执行校验和 TOFU(首次使用即信任)。关于包管理器如何使用首次使用即信任,参见包的安全性。
验证已签名的包
SE-0391 为 Swift Package Manager 增加了包签名支持。包管理器通过检查 HTTP 响应中是否存在 X-Swift-Package-Signature-Format 和 X-Swift-Package-Signature 头来判断下载到的归档是否已签名。
随后 Swift Package Manager 会根据用户的安全配置执行一系列校验。
关于包管理器注册表安全特性的更多信息,参见来自注册表的已签名包。
发布到注册表
swift package-registry publish 是一个把包发布发布到注册表的一体化命令。
包签名
注册表可以选择要求签名。关于已签名的注册表包的更多细节,参见来自注册表的已签名包。
签名格式
| 签名格式 | 规范 |
|---|---|
cms-1.0.0 | SE-391 |
由于目前只支持一种签名格式,Swift Package Manager 生成的所有签名都采用 cms-1.0.0。
被签名的内容
源代码归档
签名是分离的,会作为 HTTP 请求的一部分发送给发布 API。它也会作为 HTTP 头包含在源代码归档的下载响应中,并且是包发布元数据的一部分。
包发布元数据
签名是分离的,会作为 HTTP 请求的一部分发送给发布 API。当前的 API 规范没有提供以原始形式获取这份元数据的端点。
更多细节请参考注册表规范。
包清单文件
Package.swift 和带版本的清单文件会各自单独签名。签名嵌入在对应的清单文件中。源代码归档是在清单文件签名之后才生成并签名的。
| |
当从注册表获取清单文件时,Swift Package Manager 会通过获取包发布元数据来检查其所在的源代码归档是否已签名。如果源代码归档已签名而清单文件未签名,就会失败。包管理器会从清单文件中提取并解析签名,然后按照与源代码归档签名类似的方式验证它。
包管理器会执行发布者 TOFU,以确保它对某个包始终保持一致。这意味着清单文件和源代码归档的签名者必须是同一个。
为了减少日志输出、从而减少噪音,与清单文件签名验证相关的诊断信息被设置为 DEBUG 级别。只有当用户对未签名的包、或者用不受信任证书签名的包选择了 prompt 选项时,包管理器的行为才会和源代码归档验证一样。
Swift Package Manager 注册表配置
注册表到作用域的映射
在解析或下载注册表包时,包管理器会查看项目级和用户级配置中的注册表到作用域的映射,以确定某个包的作用域被分配给了哪个注册表。
例如,给定下面这些配置文件:
| |
- 对于包
foo.LinkedList,使用的是https://local.example.com上的注册表。(本地配置的优先级高于用户级配置。) - 对于包
bar.LinkedList,使用的是https://global.example.com上的注册表。(没有找到作用域bar的映射,因此使用[default]。)
安全配置
注册表的安全配置在用户级 registries.json(~/.swiftpm/configuration/registries.json)中指定:
| |
配置有多级覆盖。某个包的配置是用下列取值(按优先级从高到低)计算出来的:
packageOverrides(如果有)scopeOverrides(如果有)registryOverrides(如果有)default
上面例子中的 default JSON 对象包含了所有可配置的安全选项,以及在没有覆盖时所取的默认值。
signing.onUnsigned:表示包管理器将如何处理未签名的包。选项 描述 error包管理器会拒绝该包并使构建失败。 prompt包管理器会提示用户,询问是否允许这个未签名的包。 - 如果用户回答否,包管理器会拒绝该包并使构建失败。
- 如果用户回答是,并且该包此前从未被下载过,它的校验和会被保存下来,用于校验和 TOFU。否则,如果该包此前下载过,它的校验和必须与先前的值一致,否则包管理器会拒绝该包并使构建失败。
warn包管理器不会提示用户,而是在继续之前发出一个警告。 silentAllow包管理器会允许这个未签名的包,既不提示用户也不发出警告。 signing.onUntrustedCertificate:表示包管理器将如何处理用不受信任的证书签名的包。选项 描述 error包管理器会拒绝该包并使构建失败。 prompt包管理器会提示用户,询问是否允许这个用不受信任证书签名的包。 - 如果用户回答否,包管理器会拒绝该包并使构建失败。
- 如果用户回答是,包管理器会像处理未签名的包那样继续处理该包。
warn包管理器不会提示用户,而是在继续之前发出一个警告。 silentAllow包管理器会允许这个用不受信任证书签名的包,既不提示用户也不发出警告。 signing.trustedRootCertificatesPath:包含自定义受信任根证书的目录的绝对路径。包管理器会把这些根证书纳入它的信任存储,用于包签名的证书必须能链接到该存储中的根证书。这项配置允许在包、作用域和注册表级别覆盖。signing.includeDefaultTrustedRootCertificates:表示包管理器是否应该把默认的受信任根证书纳入它的信任存储。这项配置允许在包、作用域和注册表级别覆盖。signing.validationChecks:针对包签名的校验设置。校验 描述 certificateExpirationenabled:包管理器会检查下载时的当前时间是否落在签名证书的有效期内。如果不在,包管理器会拒绝该包并使构建失败。disabled:包管理器不执行这项检查。
certificateRevocation除 disabled之外,包管理器都会检查签名证书的吊销状态。目前包管理器只支持通过 OCSP 进行吊销检查。strict:吊销检查必须成功完成,并且证书必须处于正常状态。如果吊销状态为已吊销或未知(包括不支持或检查失败),包管理器会拒绝该包并使构建失败。allowSoftFail:仅当证书已被吊销时,包管理器才拒绝该包并使构建失败。包管理器允许证书的吊销状态为未知(包括不支持或检查失败)。disabled:包管理器不执行这项检查。