Sources/PackageManagerDocs/Documentation.docc/UsingSwiftPackageRegistry.md
Configure and use a package registry for Swift Package Manager.
Swift Package Manager supports downloading dependencies from any package registry that implements SE-0292 and the corresponding service specification.
In a registry, packages are identified by package identifier
in the form of scope.package-name.
A registry can be configured in Swift Package Manager at two levels:
.swiftpm/configuration/registries.json.~/.swiftpm/configuration/registries.json.One could use the swift package-registry set subcommand to assign a registry URL:
$ swift package-registry set https://packages.example.com
The above sets registry to https://packages.example.com at project level. Pass
the --global option to set registry at user level:
$ swift package-registry set --global https://packages.example.com
The resulting registries.json would look something like:
{
"registries" : {
"[default]" : {
"url": "https://packages.example.com"
}
},
"version" : 1
}
The JSON key [default] means that the registry at https://packages.example.com is "unscoped" and will be applied when there is no registry association found for a given scope.
In this example, https://packages.example.com will be applied to all scopes.
A registry package dependency is declared in Package.swift using the package identifier.
For example:
dependencies: [
.package(id: "mona.LinkedList", .upToNextMajor(from: "1.0.0")),
],
Package manager will query the registry mapped to a package's scope to resolve and download the appropriate release version.
If a registry requires authentication, it can be set up by using the swift package-registry login subcommand introduced by SE-0378.
Currently, basic and token authentication are supported.
Provide the credentials either by setting the corresponding options (i.e., one of username/password or access token) or when prompted:
$ swift package-registry login https://packages.example.com
Package manager will save the credentials to the operating system's credential store (e.g., Keychain in macOS) or netrc file (which by default is located at ~/.netrc) and apply them automatically when making registry API requests.
Resolving a registry dependency involves these steps:
For more information on resolving dependencies, see doc:ResolvingPackageVersions.
Here is an example of a source control dependency:
dependencies: [
.package(url: "https://github.com/mona/LinkedList", .upToNextMajor(from: "1.0.0")),
],
Registry can be used for source control dependencies as well.
This is particularly useful when there is a "mixed" graph (i.e., a dependency graph that has both source control and registry dependencies).
Package manager considers packages with different origins to be different, so if a package is referenced as both a registry (e.g., mona.LinkedList) and source control (e.g., https://github.com/mona/LinkedList) dependency, they are considered different even though they are the same package, and would result in symbol clashes.
Swift Package Manager can deduplicate packages by performing a lookup on the source control URL (e.g., https://github.com/mona/LinkedList) to see if it is associated with any package identifier (e.g., mona.LinkedList).
One can control if/how Package manager should use registry in conjunction with source control dependencies by setting one of these flags:
--disable-scm-to-registry-transformation (default): Swift Package Manager will not transform source control dependency to registry dependency. Source control dependency will be downloaded from its corresponding URL, while registry dependency will be resolved and downloaded using the configured registry (if any).--use-registry-identity-for-scm: Swift Package Manager will look up source control dependencies in the registry and use their registry identity whenever possible to help deduplicate packages across the two origins. In other words, suppose mona.LinkedList is the package identifier for https://github.com/mona/LinkedList, then Package manager will treat both references in the dependency graph as the same package.--replace-scm-with-registry: Swift Package Manager will look up source control dependencies in the registry and use the registry to retrieve them instead of source control when possible. In other words, Package manager will attempt to download a source control dependency from the registry first, and fall back to cloning the source repository if the dependency is not found in the registry.After a registry dependency is resolved, Swift Package Manager can download source archive of the computed package version from the registry.
As a security feature, Swift Package Manager performs checksum TOFU (trust-on-first-use) on the downloaded source archive. See doc:PackageSecurity for more information about Package manager's use of trust-on-first-use.
SE-0391 adds package signing support to Swift Package Manager.
Package manager determines if a downloaded archive is signed by checking for presence of the X-Swift-Package-Signature-Format and X-Swift-Package-Signature headers in the HTTP response.
Swift Package Manager then performs a series of validations based on user's security configuration.
For more information on Package manager's registry security features, see doc:PackageSecurity#Signed-packages-from-a-registry.
swift package-registry publish is an all-in-one command for publishing a package release to registry.
Registries can optionally require signing. For more details on signed registry packages, see doc:PackageSecurity#Signed-packages-from-a-registry.
| Signature Format | Specification |
|---|---|
cms-1.0.0 | SE-391 |
Since there is only one supported signature format, all signatures produced by Swift Package Manager are in cms-1.0.0.
The signature is detached and sent as part of the HTTP request to the publish API. It is included in the source archive download response as HTTP headers, and is part of the package release metadata.
The signature is detached and sent as part of the HTTP request to the publish API. The current API specification does not include an endpoint for fetching this metadata in its original form.
For more details, refer to the registry specification.
Package.swift and version-specific manifests are individually signed.
The signature is embedded in the corresponding manifest file.
The source archive is generated and signed after manifest signing.
// swift-tools-version: 5.7
import PackageDescription
let package = Package(
name: "library",
products: [ .library(name: "library", targets: ["library"]) ],
targets: [ .target(name: "library") ]
)
// signature: cms-1.0.0;l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw==
When a manifest is fetched from the registry, Swift Package Manager checks if the containing source archive is signed by fetching the package release metadata. It is a failure if the source archive is signed but the manifest is not. Package manager will extract and parse signature from the manifest then validate it similar to what is done for source archive signature.
Package manager performs publisher TOFU to ensure it remains consistent for the package. This implies the signer of manifests and source archive must be the same.
To reduce the amount of logging and thus noise, diagnostics related to manifest signature validation are set to DEBUG level.
Only when user chooses the prompt option for unsigned packages or packages signed with an untrusted certificate would Package manager behave like source archive validation.
When resolving or downloading registry packages, Package manager looks at the registry-to-scope mappings in project and user-level configuration to determine which registry is assigned for a package's scope.
For example, given the following configuration files:
// User-level configuration (~/.swiftpm/configuration/registries.json)
{
"registries": {
"[default]": {
"url": "https://global.example.com"
},
"foo": {
"url": "https://global.example.com"
},
},
"version": 1
}
// Local configuration (.swiftpm/configuration/registries.json)
{
"registries": {
"foo": {
"url": "https://local.example.com"
}
},
"version": 1
}
foo.LinkedList, the registry at https://local.example.com is used. (Local configuration has higher precedence than user-level configuration.)bar.LinkedList, the registry at https://global.example.com is used. (No mapping for scope bar is found, so [default] is used.)Registry security configurations are specified in the user-level registries.json (~/.swiftpm/configuration/registries.json):
{
"security": {
"default": {
"signing": {
"onUnsigned": "prompt", // One of: "error", "prompt", "warn", "silentAllow"
"onUntrustedCertificate": "prompt", // One of: "error", "prompt", "warn", "silentAllow"
"trustedRootCertificatesPath": "~/.swiftpm/security/trusted-root-certs/",
"includeDefaultTrustedRootCertificates": true,
"validationChecks": {
"certificateExpiration": "disabled", // One of: "enabled", "disabled"
"certificateRevocation": "disabled" // One of: "strict", "allowSoftFail", "disabled"
}
}
},
"registryOverrides": {
// The example shows all configuration overridable at registry level
"packages.example.com": {
"signing": {
"onUnsigned": "warn",
"onUntrustedCertificate": "warn",
"trustedRootCertificatesPath": <STRING>,
"includeDefaultTrustedRootCertificates": <BOOL>,
"validationChecks": {
"certificateExpiration": "enabled",
"certificateRevocation": "allowSoftFail"
}
}
}
},
"scopeOverrides": {
// The example shows all configuration overridable at scope level
"mona": {
"signing": {
"trustedRootCertificatesPath": <STRING>,
"includeDefaultTrustedRootCertificates": <BOOL>
}
}
},
"packageOverrides": {
// The example shows all configuration overridable at package level
"mona.LinkedList": {
"signing": {
"trustedRootCertificatesPath": <STRING>,
"includeDefaultTrustedRootCertificates": <BOOL>
}
}
}
},
...
}
There are multiple levels of overrides. A configuration for a package is computed using values from the following (in descending precedence):
packageOverrides (if any)scopeOverrides (if any)registryOverrides (if any)defaultThe default JSON object in the example above contains all configurable security options and their default value when there is no override.
signing.onUnsigned: Indicates how Package manager will handle an unsigned package.
| Option | Description |
|---|---|
error | Package manager will reject the package and fail the build. |
prompt | Package manager will prompt user to see if the unsigned package should be allowed. <ul><li>If no, Package manager will reject the package and fail the build.</li><li>If yes and the package has never been downloaded, its checksum will be stored for checksum TOFU. Otherwise, if the package has been downloaded before, its checksum must match the previous value or else Package manager will reject the package and fail the build.</li></ul> Package manager will record user's response to prevent repetitive prompting. |
warn | Package manager will not prompt user but will emit a warning before proceeding. |
silentAllow | Package manager will allow the unsigned package without prompting user or emitting warning. |
signing.onUntrustedCertificate: Indicates how Package manager will handle a package signed with an untrusted certificate.
| Option | Description |
|---|---|
error | Package manager will reject the package and fail the build. |
prompt | Package manager will prompt user to see if the package signed with an untrusted certificate should be allowed. <ul><li>If no, Package manager will reject the package and fail the build.</li><li>If yes, Package manager will proceed with the package as if it were an unsigned package.</li></ul> Package manager will record user's response to prevent repetitive prompting. |
warn | Package manager will not prompt user but will emit a warning before proceeding. |
silentAllow | Package manager will allow the package signed with an untrusted certificate without prompting user or emitting warning. |
signing.trustedRootCertificatesPath: Absolute path to the directory containing custom trusted roots. Package manager will include these roots in its trust store, and certificates used for package signing must chain to roots found in this store. This configuration allows override at the package, scope, and registry levels.
signing.includeDefaultTrustedRootCertificates: Indicates if Package manager should include default trusted roots in its trust store. This configuration allows override at the package, scope, and registry levels.
signing.validationChecks: Validation check settings for the package signature.
| Validation | Description |
|---|---|
certificateExpiration | <ul><li>enabled: Package manager will check that the current timestamp when downloading falls within the signing certificate's validity period. If it doesn't, Package manager will reject the package and fail the build.</li><li>disabled: Package manager will not perform this check.</li></ul> |
certificateRevocation | With the exception of disabled, Package manager will check revocation status of the signing certificate. Currently, Package manager only supports revocation check done through OCSP.<ul><li>strict: Revocation check must complete successfully and the certificate must be in good status. Package manager will reject the package and fail the build if the revocation status is revoked or unknown (including revocation check not supported or failed).</li><li>allowSoftFail: Package manager will reject the package and fail the build iff the certificate has been revoked. Package manager will allow the certificate's revocation status to be unknown (including revocation check not supported or failed).</li><li>disabled: Package manager will not perform this check.</li></ul> |