diff --git a/Sources/PackageManagerDocs/Documentation.docc/Documentation.md b/Sources/PackageManagerDocs/Documentation.docc/Documentation.md index 6d24d581274..5fe6b4599f7 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/Documentation.md +++ b/Sources/PackageManagerDocs/Documentation.docc/Documentation.md @@ -32,6 +32,7 @@ The Swift Package Manager lets you share your code as a package, depend on and u - - - +- - - - @@ -56,3 +57,7 @@ The Swift Package Manager lets you share your code as a package, depend on and u - - - + +### Design + +- diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index 91216260af6..424e1c88625 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -8,18 +8,11 @@ Learn to create, publish and use Swift package collections. ## Overview -Package collections, introduced by [SE-0291](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0291-package-collections.md), are -curated lists of packages and associated metadata that can be imported -by SwiftPM to make discovery of existing packages easier. -They are authored as static JSON documents -and can be published to the web or distributed to local file systems. - -Educators and community influencers can publish -package collections to go along with course materials or blog posts, removing the friction of using -packages for the first time and the cognitive overload of deciding which packages are useful for -a particular task. -Enterprises may use collections to narrow the decision space for their internal -engineering teams, focusing them on a trusted set of vetted packages. +Package collections, introduced by [SE-0291](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0291-package-collections.md), are curated lists of packages and associated metadata that you can import to make discovery of existing packages easier. + +Educators and community influencers can publish package collections to go along with course materials or blog posts, making it easier for their readers to use packages for the first time, or choosing which packages to use for a particular task. +Enterprises may use collections to provide a trusted set of packages, or a collection of packages consistently used by a team. +You can author a package collection as a static JSON document and publish it to the web or distribute it on a local file system. ### Using the package-collection CLI @@ -46,8 +39,9 @@ intended for package collection publishers: - [`package-collection-validate`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionValidator): Perform basic validations on a package collection - [`package-collection-diff`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionDiff): Compare two package collections to see if their contents are different -All package collections must adhere to the [collection data format]() for SwiftPM to be able to consume them. The recommended way -to create package collections is to use [`package-collection-generate`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionGenerator). For custom implementations, the data models are available through the [`PackageCollectionsModel` module](https://github.com/swiftlang/swift-package-manager/tree/main/Sources/PackageCollectionsModel). +All package collections must adhere to the [collection data format]() for SwiftPM to be able to consume them. +The recommended way to create package collections is to use [`package-collection-generate`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionGenerator). +For custom implementations, the data models are available through the [`PackageCollectionsModel` module](https://github.com/swiftlang/swift-package-manager/tree/main/Sources/PackageCollectionsModel). #### Input Format @@ -68,7 +62,7 @@ To begin, define the top-level metadata about the collection: Each item in the `packages` array is a package object with the following properties: * `url`: The URL of the package. Currently only Git repository URLs are supported. URL should be HTTPS and may contain `.git` suffix. -* `identity`: The [identity](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#36-package-identification) of the package if published to registry. **Optional.** +* `identity`: The [identity]() of the package if published to a registry. **Optional.** * `summary`: A description of the package. **Optional.** * `keywords`: An array of keywords that the package is associated with. **Optional.** * `readmeURL`: The URL of the package's README. **Optional.** @@ -77,8 +71,6 @@ Each item in the `packages` array is a package object with the following propert * `name`: License name. [SPDX identifier](https://spdx.org/licenses/) (e.g., `Apache-2.0`, `MIT`, etc.) preferred. Omit if unknown. **Optional.** * `versions`: An array of version objects representing the most recent and/or relevant releases of the package. -When a package is [added to a collection](), the package object will appear in the collection's `packages` array with the properties described above. - ### Add versions to a package A version object has metadata extracted from `Package.swift` and optionally additional metadata from other sources: @@ -144,7 +136,7 @@ A version object has metadata extracted from `Package.swift` and optionally addi * `name`: License name. [SPDX identifier](https://spdx.org/licenses/) (e.g., `Apache-2.0`, `MIT`, etc.) preferred. Omit if unknown. **Optional.** * `author`: The package version's author. **Optional.** * `name`: The author of the package version. -* `signer`: The signer of the package version. **Optional.** Refer to [documentation](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md#package-signing) on package signing for details. +* `signer`: The signer of the package version. **Optional.** Refer to the [documentation]() on package signing for details. * `type`: The signer type. Currently the only valid value is `ADP` (Apple Developer Program). * `commonName`: The common name of the signing certificate's subject. * `organizationalUnitName`: The organizational unit name of the signing certificate's subject. @@ -153,7 +145,7 @@ A version object has metadata extracted from `Package.swift` and optionally addi ### Version-specific manifests -Package collection generators should include data from the "default" manifest `Package.swift` as well as [version-specific manifest(s)](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/Usage.md#version-specific-manifest-selection) . +Package collection generators should include data from the "default" manifest `Package.swift` as well as [version-specific manifest(s)]() The keys of the `manifests` map are Swift tools (semantic) versions: * For `Package.swift`, the tools version specified in `Package.swift` should be used. @@ -161,16 +153,14 @@ The keys of the `manifests` map are Swift tools (semantic) versions: ### Version-specific tags - [Version-specific tags](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/Usage.md#version-specific-tag-selection) are not - supported by package collections. +[Version-specific tags]() are not supported by package collections. ### Configuration File Configuration that pertains to package collections are stored in the file `~/.swiftpm/config/collections.json`. -It keeps track of user's list of configured collections -and preferences such as those set by the `--trust-unsigned` and `--skip-signature-check` flags in the [`package-collection add` command](). +It keeps track of user's list of configured collections and preferences such as those set by the `--trust-unsigned` and `--skip-signature-check` flags in the [`package-collection add` command](). -> Note: This file is managed through SwiftPM commands and users are not expected to edit it by hand. +> Note: This file is managed through Swift Package Manager commands and users are not expected to edit it by hand. ## Example @@ -300,72 +290,24 @@ and preferences such as those set by the `--trust-unsigned` and `--skip-signatur } ``` +## Protecting package collections -## Signing and protecting package collections +### Signing a collection -Package collections can be signed to establish authenticity and protect their integrity. +[Sign package collections]() to establish authenticity and protect their integrity. Doing this is optional. Users will be prompted for confirmation before they can add an [unsigned collection](). +The signing certificate you use to sign a package collection must meet a list of [requirements](). If these requirements are not met, the package manager returns an error. -[`package-collection-sign`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionSigner) helps publishers sign their package -collections. To generate a signature one must provide: -- The package collection file to be signed -- A code signing certificate (DER-encoded) -- The certificate's private key (PEM-encoded) -- The certificate's chain in its entirety +For more details on the security features Package manager implements, see . -A signed package collection has an extra `signature` object: - -```json -{ - ..., - "signature": { - "signature": "", - "certificate": { - "subject": { - "commonName": "Jane Doe", - ... - }, - "issuer": { - "commonName": "Sample CA", - ... - } - } - } -} -``` - -- The signature string (represented by `""`) is used to verify the contents of the collection file haven't been tampered with since it was signed when SwiftPM user [adds the collection]() to their configured list of collections. It includes the certificate's public key and chain. -- `certificate` contains details extracted from the signing certificate. `subject.commonName` should be consistent with the name of the publisher so that it's recognizable by users. The root of the certificate must be [installed and trusted on users' machines](). - -### Requirements on signing certificate - -Certificates used for signing package collections must meet the following requirements, which are checked and enforced during signature generation (publishers) and verification (SwiftPM users): -- The timestamp at which signing/verification is done must fall within the signing certificate's validity period. -- The certificate's "Extended Key Usage" extension must include "Code Signing". -- The certificate must use either 256-bit EC (recommended for enhanced security) or 2048-bit RSA key. -- The certificate must not be revoked. The certificate authority must support OCSP, which means the certificate must have the "Certificate Authority Information Access" extension that includes OCSP as a method, specifying the responder's URL. -- The certificate chain is valid and root certificate must be trusted. - -Non-expired, non-revoked Swift Package Collection certificates from [developer.apple.com](https://developer.apple.com) satisfy all of the criteria above. - -#### Trusted root certificates - -With the `package-collection-sign` tool, the root certificate provided as input for signing a collection is automatically trusted. When SwiftPM user tries to add the collection, however, -the root certificate must either be preinstalled with the OS (Apple platforms only) or found in the `~/.swiftpm/config/trust-root-certs` directory (all platforms) or shipped with -the [certificate-pinning configuration](), otherwise the [signature check]() will fail. -Collection publishers should make the DER-encoded -root certificate(s) that they use downloadable so that users can adjust their setup if needed. - - -## Protecting package collections +### Security risks -[Signing]() can provide some degree of protection on package collections and reduce the risks of their contents being modified by malicious actors, but it doesn't -prevent the following attack vectors: -- **Signature stripping**: This involves attackers removing signature from a signed collection, causing it to be downloaded as an [unsigned collection]() and bypassing signature check. In this case, publishers should make it known that the collection is signed, and SwiftPM users should abort the `add` operation when the "unsigned" warning appears on a supposedly signed collection. +While signing can provide some degree of protection on package collections and reduce the risks of their contents being modified by malicious actors, it doesn't prevent the following attack vectors: +- **Signature stripping**: This involves attackers removing signature from a signed collection, causing it to be downloaded as an unsigned collection and bypassing signature check. In this case, publishers should make it known that the collection is signed, and SwiftPM users should abort the `add` operation when the "unsigned" warning appears on a supposedly signed collection. - **Signature replacement**: Attackers may modify a collection then re-sign it using a different certificate, either pretend to be the same entity or as some other entity, and SwiftPM will accept it as long as the [signature is valid](). -To defend against these attacks, SwiftPM has certificate-pinning configuration that allows collection publishers to: +To defend against these attacks, package manager has certificate-pinning configuration that allows collection publishers to: - Require signature check on their collections — this defends against "signature stripping". - Restrict what certificate can be used for signing — this defends against "signature replacement". diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md index 1a1bb186d2d..80424594f46 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md @@ -32,12 +32,9 @@ Added "Sample Package Collection" to your package collections. ### Signed package collections -Package collection publishers may [sign a collection to protect its contents]() from being tampered with. -If a collection is signed, SwiftPM will check that the -signature is valid before importing it and return an error if any of these fails: -- The file's contents, signature excluded, must match what was used to generate the signature. -In other words, this checks to see if the collection has been altered since it was signed. -- The signing certificate must meet all the [requirements](). +Publishers of a package collection may [sign a collection to protect its contents](). +The package manager will check if a signed collection's signature is valid before importing it. +If the validation check fails, the package manager returns an error: ```bash $ swift package-collection add https://www.example.com/bad-packages.json @@ -50,8 +47,8 @@ Users may continue adding the collection despite the error or preemptively skip $ swift package-collection add https://www.example.com/packages.json --skip-signature-check ``` -For package collections hosted on the web, publishers may ask SwiftPM to [enforce the signature requirement](). If a package collection is -expected to be signed but it isn't, user will see the following error message: +For package collections hosted on the web, publishers may ask the package manager to [enforce the signature requirement](). +If a package collection is expected to be signed but it isn't, users will see the following error message: ```bash $ swift package-collection add https://www.example.com/bad-packages.json @@ -60,15 +57,11 @@ The collection is missing required signature, which means it might have been com Users should NOT add the package collection in this case. -##### Trusted root certificates - -Since generating a collection signature requires a certificate, part of the signature check involves validating the certificate and its chain and making sure that the root certificate is trusted. +For more details on signature validation, see . -On Apple platforms, all root certificates that come preinstalled with the OS are automatically trusted. Users may include additional certificates to trust by placing -them in the `~/.swiftpm/config/trust-root-certs` directory. +##### Trusted root certificates -On non-Apple platforms, there are no trusted root certificates by default other than those shipped with the [certificate-pinning configuration](). Only those -found in `~/.swiftpm/config/trust-root-certs` are trusted. This means that the signature check will always fail unless the `trust-root-certs` directory is set up: +The package manager [validates the certificate]() of a signed collection as a part of its signature validation to make sure that the root certificate is trusted. ```bash $ swift package-collection add https://www.example.com/packages.json @@ -76,8 +69,7 @@ The collection's signature cannot be verified due to missing configuration. ``` Users can explicitly specify they trust a publisher and any collections they publish, by obtaining that publisher's root certificate and saving it to `~/.swiftpm/config/trust-root-certs`. The -root certificates must be DER-encoded. Since SwiftPM trusts all certificate chains under a root, depending on what roots are installed, some publishers may already be trusted implicitly and -users don't need to explicitly specify each one. +root certificates must be DER-encoded. Since the package manager trusts all certificate chains under a root, depending on what roots are installed, some publishers may already be trusted implicitly and users don't need to explicitly specify each one. #### Unsigned package collections @@ -88,7 +80,7 @@ $ swift package-collection add https://www.example.com/packages.json The collection is not signed. If you would still like to add it please rerun 'add' with '--trust-unsigned'. ``` -To continue user must confirm their trust by passing the `--trust-unsigned` flag: +To continue, users must confirm their trust by passing the `--trust-unsigned` flag: ```bash $ swift package-collection add https://www.example.com/packages.json --trust-unsigned diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryLogin.md b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryLogin.md index 284c8032208..bd10fbfaa99 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryLogin.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryLogin.md @@ -7,6 +7,230 @@ Log in to a registry. +## Overview + +The package manager verifies the credentials using the registry service's login API. +If it returns a successful response, the credentials are persisted to the operating system's credential store (for example, Keychain in macOS). On non-macOS platforms, or if the `--netrc` flag is provided, the credentials are persisted to the user-level .netrc (which by default is located at `~/.netrc`). +The user-level configuration file located at ~/.swiftpm/configuration/registries.json is also updated. + +The `url` should be the registry's base URL (for example, `https://example-registry.com`). +If the location of the login API endpoint is not `/login` (for example, `https://example-registry.com/api/v1/login`), provide the full URL. + +The URL must be HTTPS. + +The table below shows the supported authentication types and their required option(s): + +| Authentication Method | Required Option(s) | +| ----------------------- | ------------------------- | +| Basic | --username, --password | +| Token | --token | + +The tool analyzes the provided options to determine the authentication type and prompt (that is, interactive mode) for the password/token if it is missing. +For example, if only `--username` is present, the tool assumes basic authentication and prompts for the password. + +For non-interactive mode, provide the `--password` or `--token` option as required or make sure the secret is present in credential storage. + +If the operating system's credential store is not supported, the tool prompts the user for confirmation before writing credentials to the less secure netrc file. +Use `--no-confirm` to disable this confirmation. + +To force usage of netrc file instead of the operating system's credential store, pass the `--netrc` flag. + +### Example: basic authentication (macOS, interactive) + +```bash +> swift package-registry login https://example-registry.com \ + --username jappleseed +Enter password for 'jappleseed': + +Login successful. +Credentials have been saved to the operating system's secure credential store. +``` + +An entry for `example-registry.com` is added to Keychain. + +Package manager updated `registries.json` to indicate that `example-registry.com` requires basic authentication: + +{ + "authentication": { + "example-registry.com": { + "type": "basic" + }, + ... + }, + ... +} + +### Example: basic authentication (operating system's credential store not supported, interactive) + +```bash +> swift package-registry login https://example-registry.com \ + --username jappleseed +Enter password for 'jappleseed': + +Login successful. + +WARNING: Secure credential store is not supported on this platform. +Your credentials will be written out to netrc file. +Continue? (Yes/No): Yes + +Credentials have been saved to netrc file. +``` +An entry for `example-registry.com` is added to the netrc file: + +```bash +machine example-registry.com +login jappleseed +password alpine +``` + +Package manager updates `registries.json` to indicate that example-registry.com requires basic authentication: + +```json +{ + "authentication": { + "example-registry.com": { + "type": "basic" + }, + ... + }, + ... +} +``` + +### Example: basic authentication (use netrc file instead of operating system's credential store, interactive) + +```bash +> swift package-registry login https://example-registry.com \ + --username jappleseed + --netrc +Enter password for 'jappleseed': + +Login successful. + +WARNING: You choose to use netrc file instead of the operating system's secure credential store. +Your credentials will be written out to netrc file. +Continue? (Yes/No): Yes + +Credentials have been saved to netrc file. +``` + +An entry for `example-registry.com` is added to the netrc file: + +```bash +machine example-registry.com +login jappleseed +password alpine +``` + +Package manager updates `registries.json` to indicate that `example-registry.com` requires basic authentication: + +```json +{ + "authentication": { + "example-registry.com": { + "type": "basic" + }, + ... + }, + ... +} +``` + +### Example: basic authentication (operating system's credential store not supported, non-interactive) + +```bash +> swift package-registry login https://example-registry.com \ + --username jappleseed \ + --password alpine \ + --no-confirm + +Login successful. +Credentials have been saved to netrc file. +``` + +An entry for `example-registry.com` is added to the netrc file: + +```bash +machine example-registry.com +login jappleseed +password alpine +``` +Package manager updates `registries.json` to indicate that `example-registry.com` requires basic authentication: + +```json +{ + "authentication": { + "example-registry.com": { + "type": "basic" + }, + ... + }, + ... +} +``` + +### Example: basic authentication (operating system's credential store not supported, non-interactive, non-default login URL) + +```bash +> swift package-registry login https://example-registry.com/api/v1/login \ + --username jappleseed \ + --password alpine \ + --no-confirm + +Login successful. +Credentials have been saved to netrc file. +``` +An entry for `example-registry.com` is added to the netrc file: + +```bash +machine example-registry.com +login jappleseed +password alpine +``` +Package manager updates `registries.json` to indicate that `example-registry.com` requires basic authentication: + +```json +{ + "authentication": { + "example-registry.com": { + "type": "basic", + "loginAPIPath": "/api/v1/login" + }, + ... + }, + ... +} +``` + +### Example: token authentication + +```bash +> swift package-registry login https://example-registry.com \ + --token jappleseedstoken +``` +An entry for `example-registry.com` is added to the operating system's credential store if supported, or the user-level netrc file otherwise: + +```bash +machine example-registry.com +login token +password jappleseedstoken +``` +Package manager updates `registries.json` to indicate that `example-registry.com` requires token authentication: + +```json +{ + "authentication": { + "example-registry.com": { + "type": "token" + }, + ... + }, + ... +} +``` + +### Usage + ``` package-registry login [--package-path=] [--cache-path=] [--config-path=] [--security-path=] [--scratch-path=] [--swift-sdks-path=] [--toolset=...] [--pkg-config-path=...] [--enable-dependency-cache|disable-dependency-cache] [--enable-build-manifest-caching|disable-build-manifest-caching] [--manifest-cache=] [--enable-experimental-prebuilts|disable-experimental-prebuilts] [--verbose] [--very-verbose|vv] [--quiet] [--color-diagnostics|no-color-diagnostics] [--disable-sandbox] [--netrc] [--enable-netrc|disable-netrc] [--netrc-file=] [--enable-keychain|disable-keychain] [--resolver-fingerprint-checking=] [--resolver-signing-entity-checking=] [--enable-signature-validation|disable-signature-validation] [--enable-prefetching|disable-prefetching] [--force-resolved-versions|disable-automatic-resolution|only-use-versions-from-resolved-file] [--skip-update] [--disable-scm-to-registry-transformation] [--use-registry-identity-for-scm] [--replace-scm-with-registry] [--default-registry-url=] [--configuration=] [--=...] [--=...] [--=...] [--=...] [--triple=] [--sdk=] [--toolchain=] [--swift-sdk=] [--sanitize=...] [--auto-index-store|enable-index-store|disable-index-store] [--enable-parseable-module-interfaces] [--jobs=] [--use-integrated-swift-driver] [--explicit-target-dependency-import-check=] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [] [--username=] [--password=] [--token=] [--token-file=] [--no-confirm] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryLogout.md b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryLogout.md index b471f859822..1b5086147b6 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryLogout.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryLogout.md @@ -5,7 +5,45 @@ @Available("Swift", introduced: "5.9") } -Log out from a registry +Log out from a registry. + +## Overview + +Package manager removes credentials from the operating system's credential store if supported, and the user-level configuration file (`registries.json`). + +To avoid accidental removal of sensitive data, the `netrc` file needs to be updated manually by the user. + +### Changes to registry configuration + +The `authentication` key in the user-level `registries.json` file by default is located at `~/.swiftpm/configuration/registries.json`. Any package registry that requires authentication must have a corresponding entry in this dictionary. + +```json +{ + "registries": { + "[default]": { + "url": "https://example-registry.com" + } + }, + "authentication": { + "example-registry.com": { + "type": , // One of: "basic", "token" + "loginAPIPath": // Optional. Overrides the default API path (i.e., /login). + } + }, + "version": 1 +} +``` + +`type` must be one of the following: + +- `basic`: username and password +- `token`: access token + +Specify credentials in the native credential store of the operating system if supported, otherwise in the user-level netrc file. + +See [credential storage](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0378-package-registry-auth.md#credential-storage) for more details on configuring credentials for each authentication type. + +### Usage ``` package-registry logout [--package-path=] [--cache-path=] [--config-path=] [--security-path=] [--scratch-path=] [--swift-sdks-path=] [--toolset=...] [--pkg-config-path=...] [--enable-dependency-cache|disable-dependency-cache] [--enable-build-manifest-caching|disable-build-manifest-caching] [--manifest-cache=] [--enable-experimental-prebuilts|disable-experimental-prebuilts] [--verbose] [--very-verbose|vv] [--quiet] [--color-diagnostics|no-color-diagnostics] [--disable-sandbox] [--netrc] [--enable-netrc|disable-netrc] [--netrc-file=] [--enable-keychain|disable-keychain] [--resolver-fingerprint-checking=] [--resolver-signing-entity-checking=] [--enable-signature-validation|disable-signature-validation] [--enable-prefetching|disable-prefetching] [--force-resolved-versions|disable-automatic-resolution|only-use-versions-from-resolved-file] [--skip-update] [--disable-scm-to-registry-transformation] [--use-registry-identity-for-scm] [--replace-scm-with-registry] [--default-registry-url=] [--configuration=] [--=...] [--=...] [--=...] [--=...] [--triple=] [--sdk=] [--toolchain=] [--swift-sdk=] [--sanitize=...] [--auto-index-store|enable-index-store|disable-index-store] [--enable-parseable-module-interfaces] [--jobs=] [--use-integrated-swift-driver] [--explicit-target-dependency-import-check=] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [] [--version] [--help] diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryPublish.md b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryPublish.md index 285e7009b42..c48bd0c3690 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryPublish.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryPublish.md @@ -7,6 +7,38 @@ Publish to a registry. +## Overview + +This command creates a source archive for the package release, optionally signs it, and finally [publishes the package release]() to the registry. + +If authentication is required for package publication, package authors should [configure registry login]() before running `publish`. + +### Publisher TOFU + +Some certificates allow the package manager to extract additional information about the signing identity. For packages signed with these certificates, package manager performs publisher TOFU (trust-on-first-use) to ensure the signer remains the same across all versions of the package. + +The `--resolver-signing-entity-checking` option controls whether a publisher mismatch should result in a warning (`warn`) or error (`strict`). Data used by publisher TOFU is saved to `~/.swiftpm/security/signing-entities/`. + +For more details on trust-on-first-use, see . + +#### Package release metadata + +Package authors can specify a custom location of the package release metadata file by setting the `--metadata-path` option of the `publish` subcommand. +Otherwise, package manager looks for a file named `package-metadata.json` in the package directory. + +Contents of the metadata file must conform to the [JSON schema](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md#package-release-metadata-standards) defined in SE-0391. + +Refer to the [registry specification]() for any additional requirements. + +#### Package signing + +If a registry requires signing, package authors need to sign the package release by either setting the `signing-identity` (for reading from operating system's identity store such as Keychain in macOS), or `private-key-path` and `cert-chain-paths` (for reading from files) options of the `publish` subcommand. +This allows Package manager to locate the signing key and certificate. + +For more information on package signing, see . + +### Usage + ``` package-registry publish [--package-path=] [--cache-path=] [--config-path=] [--security-path=] [--scratch-path=] [--swift-sdks-path=] [--toolset=...] [--pkg-config-path=...] [--enable-dependency-cache|disable-dependency-cache] [--enable-build-manifest-caching|disable-build-manifest-caching] [--manifest-cache=] [--enable-experimental-prebuilts|disable-experimental-prebuilts] [--verbose] [--very-verbose|vv] [--quiet] [--color-diagnostics|no-color-diagnostics] [--disable-sandbox] [--netrc] [--enable-netrc|disable-netrc] [--netrc-file=] [--enable-keychain|disable-keychain] [--resolver-fingerprint-checking=] [--resolver-signing-entity-checking=] [--enable-signature-validation|disable-signature-validation] [--enable-prefetching|disable-prefetching] [--force-resolved-versions|disable-automatic-resolution|only-use-versions-from-resolved-file] [--skip-update] [--disable-scm-to-registry-transformation] [--use-registry-identity-for-scm] [--replace-scm-with-registry] [--default-registry-url=] [--configuration=] [--=...] [--=...] [--=...] [--=...] [--triple=] [--sdk=] [--toolchain=] [--swift-sdk=] [--sanitize=...] [--auto-index-store|enable-index-store|disable-index-store] [--enable-parseable-module-interfaces] [--jobs=] [--use-integrated-swift-driver] [--explicit-target-dependency-import-check=] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--url|registry-url=] [--scratch-directory=] [--metadata-path=] [--signing-identity=] [--private-key-path=] [--cert-chain-paths=...] [--allow-insecure-http] [--dry-run] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistrySet.md b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistrySet.md index 408413af5cc..e99d9935069 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistrySet.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistrySet.md @@ -7,6 +7,65 @@ Set a custom registry. +## Overview + +Use this subcommand to assign a registry at project or user-level. + +### Project-level + +```bash +$ swift package-registry set https://packages.example.com +``` + +At the project level, package manager uses the registry for packages within the project with the registry settings stored in `.swiftpm/configuration/registries.json`. + +### User-level + +When you pass the `--global` option, the package manager sets the registry at the user-level: + +```bash +$ swift package-registry set --global https://global.example.com +``` + +At the user level, the package manager uses the registry for all projects for that user with the registry settings stored in `~/.swiftpm/configuration/registries.json`. + + +### Registry settings + +An example of the `registries.json` that would result from the user-level setting from above would look something like: + +```json +{ + "registries" : { + "[default]" : { + "url": "https://global.example.com" + } + }, + "version" : 1 +} +``` + +The JSON key `[default]` means that the registry at `https://global.example.com` is "unscoped" and will be applied when there is no registry association found for a given scope. + +### Setting a scope + +To set a specific scope: + +```bash +# project-level +$ swift package-registry set --scope foo https://local.example.com + +# user-level +$ swift package-registry set --scope foo --global https://global.example.com +``` + +### Removing a registry + +To remove a registry assignment, use the [`swift package-registry unset` subcommand](). + + +### Usage + ``` package-registry set [--package-path=] [--cache-path=] [--config-path=] [--security-path=] [--scratch-path=] [--swift-sdks-path=] [--toolset=...] [--pkg-config-path=...] [--enable-dependency-cache|disable-dependency-cache] [--enable-build-manifest-caching|disable-build-manifest-caching] [--manifest-cache=] [--enable-experimental-prebuilts|disable-experimental-prebuilts] [--verbose] [--very-verbose|vv] [--quiet] [--color-diagnostics|no-color-diagnostics] [--disable-sandbox] [--netrc] [--enable-netrc|disable-netrc] [--netrc-file=] [--enable-keychain|disable-keychain] [--resolver-fingerprint-checking=] [--resolver-signing-entity-checking=] [--enable-signature-validation|disable-signature-validation] [--enable-prefetching|disable-prefetching] [--force-resolved-versions|disable-automatic-resolution|only-use-versions-from-resolved-file] [--skip-update] [--disable-scm-to-registry-transformation] [--use-registry-identity-for-scm] [--replace-scm-with-registry] [--default-registry-url=] [--configuration=] [--=...] [--=...] [--=...] [--=...] [--triple=] [--sdk=] [--toolchain=] [--swift-sdk=] [--sanitize=...] [--auto-index-store|enable-index-store|disable-index-store] [--enable-parseable-module-interfaces] [--jobs=] [--use-integrated-swift-driver] [--explicit-target-dependency-import-check=] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--global] [--scope=] [--allow-insecure-http] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryUnset.md b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryUnset.md index b98e31e64d5..e37ff005f84 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryUnset.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageRegistry/PackageRegistryUnset.md @@ -7,6 +7,8 @@ Remove a configured registry. +### Usage + ``` package-registry unset [--package-path=] [--cache-path=] [--config-path=] [--security-path=] [--scratch-path=] [--swift-sdks-path=] [--toolset=...] [--pkg-config-path=...] [--enable-dependency-cache|disable-dependency-cache] [--enable-build-manifest-caching|disable-build-manifest-caching] [--manifest-cache=] [--enable-experimental-prebuilts|disable-experimental-prebuilts] [--verbose] [--very-verbose|vv] [--quiet] [--color-diagnostics|no-color-diagnostics] [--disable-sandbox] [--netrc] [--enable-netrc|disable-netrc] [--netrc-file=] [--enable-keychain|disable-keychain] [--resolver-fingerprint-checking=] [--resolver-signing-entity-checking=] [--enable-signature-validation|disable-signature-validation] [--enable-prefetching|disable-prefetching] [--force-resolved-versions|disable-automatic-resolution|only-use-versions-from-resolved-file] [--skip-update] [--disable-scm-to-registry-transformation] [--use-registry-identity-for-scm] [--replace-scm-with-registry] [--default-registry-url=] [--configuration=] [--=...] [--=...] [--=...] [--=...] [--triple=] [--sdk=] [--toolchain=] [--swift-sdk=] [--sanitize=...] [--auto-index-store|enable-index-store|disable-index-store] [--enable-parseable-module-interfaces] [--jobs=] [--use-integrated-swift-driver] [--explicit-target-dependency-import-check=] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--global] [--scope=] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageSecurity.md b/Sources/PackageManagerDocs/Documentation.docc/PackageSecurity.md index 5ed1d1ce75b..1491a586955 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageSecurity.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageSecurity.md @@ -27,6 +27,121 @@ under the `~/.swiftpm/security/fingerprints` directory. - For a registry package, the fingerprint filename takes the form of `{PACKAGE_ID}.json` (such as `mona.LinkedList.json`). For packages retrieved from a registry, the package manager expects all registries to provide consistent fingerprints for packages they host. -If registries have conflicting fingerprints, package manager reports that as an error. -This can be tuned down to warning by setting the [build]() option `--resolver-fingerprint-checking` -to `warn` (default is `strict`). +If the archive is downloaded for the first time, the package manager [fetches metadata of the package release]() to obtain the expected checksum. +Otherwise, the package manager compares the checksum with that in local storage (`~/.swiftpm/security/fingerprints/`), saved from previous download. + +If registries have conflicting fingerprints, the package manager reports an error. +You can reduce the error to a warning by setting the [build]() option `--resolver-fingerprint-checking` to `warn` (default is `strict`). + +### Package signing + +#### Signed packages from a registry + +A registry may support or require signing. +To sign a package release, package authors set either the `signing-identity` (for reading from operating system's identity store such as Keychain in macOS), or `private-key-path` and `cert-chain-paths` (for reading from files) options of the [`swift package-registry publish`]() subcommand so the package manager can locate the signing key and certificate. + +If the certificate chain's root and intermediates are known by the package manager, the package author would only needs to provide the leaf signing certificate in `cert-chain-paths`. + +Otherwise, the package author should be provide the entire certificate chain as `cert-chain-paths` so that all of the certificates are included in the signature, making it possible for the package manager to reconstruct the certificate chain for validation later. +This is applicable to `signing-identity` as well. That is, you can use `signing-identity` in combination with `cert-chain-paths` to provide the entire certificate chain. + +If the root of the signing certificate is not in the package manager's default trust store, the package author is responsible for telling package users to include the root certificate in their local [trust roots]() directory, otherwise [signature validation]() may fail upon download because the signing certificate is not trusted. + +For more information on signed registry packages, see . + +##### Validating signed packages + +The 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. + +It then performs a series of validations based on user's [security configuration](). +- If the archive is unsigned, the package manager will error/prompt/warn/allow based on the `signing.onUnsigned` configuration. +- If the archive is signed, the package manage validates the signature and the signing certificate chain. + +###### Trusted vs. untrusted certificate + +A certificate is trusted if it is chained to any root in the package manager's trust store, which consists of: +- The package manager's default trust store, if `signing.includeDefaultTrustedRootCertificates` is `true`. +- Custom root(s) in the configured trusted roots directory at `signing.trustedRootCertificatesPath`. Certificates must be DER-encoded. + +Otherwise, a certificate is untrusted and handled according to the `signing.onUntrustedCertificate` configuration. +If a user opts to continue with the untrusted certificate, the package manager proceeds as if it were an unsigned package. + +###### Certificate policies + +The package manager requires all certificates used for package signing to have the "code signing" extended key usage extension. They must also satisfy the core policies from [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280), as implemented by [swift-certificates](https://github.com/apple/swift-certificates). + +Users can configure certificate expiry and revocation check through the `signing.validationChecks.certificateExpiration` and `signing.validationChecks.certificateRevocation` configuration, respectively. Note that revocation check implicitly requires expiry check. + +An invalid signing certificate would result in the package manager rejecting the archive when downloading from a registry, or the package collection. + +#### Signed package collections + +Package collection publishers may [sign a collection to protect its contents]() from tampering. +If a collection is signed, the package manager checks that the signature is valid before importing it; or returns an error if any of these fails: +- The file's contents, signature excluded, must match what was used to generate the signature. +In other words, this checks to see if the collection was altered after it was signed. +- The signing certificate must meet all the [requirements](). + +Since signing a package collection is optional, the package manager prompts users for confirmation before they can add an [unsigned collection](). + + [`package-collection-sign`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionSigner) helps publishers sign their package collections. + To generate a signature you need to provide: + - The package collection file to be signed. + - A DER-encoded code signing certificate. + - The PEM-encoded certificate's private key. + - The certificate's chain in its entirety. + + A signed package collection has an extra `signature` object: + + ```json + { + ..., + "signature": { + "signature": "", + "certificate": { + "subject": { + "commonName": "Jane Doe", + ... + }, + "issuer": { + "commonName": "Sample CA", + ... + } + } + } + } + ``` + + - The package manager uses the signature string (represented by `""`) is used to verify the contents of the collection file haven't been tampered with after it was signed. The package manager signs the collection when a user [adds the collection]() to their configured list of collections. It includes the certificate's public key and chain. + - `certificate` contains details extracted from the signing certificate. `subject.commonName` should be consistent with the name of the publisher so that it's recognizable by users. The root of the certificate must be [installed and trusted on users' machines](). + +For more information on adding signed package collections, see . + +###### Requirements on signing certificate + +Certificates used for signing package collections must meet the following requirements, which are checked and enforced during signature generation (publishers) and verification (Swift Package Manager users): +- The timestamp at which signing/verification is done must fall within the signing certificate's validity period. +- The certificate's "Extended Key Usage" extension must include "Code Signing". +- The certificate must use either 256-bit EC (recommended for enhanced security) or 2048-bit RSA key. +- The certificate must not be revoked. The certificate authority must support OCSP, which means the certificate must have the "Certificate Authority Information Access" extension that includes OCSP as a method, specifying the responder's URL. +- The certificate chain is valid and root certificate must be trusted. + +Non-expired, non-revoked Swift Package Collection certificates from [developer.apple.com](https://developer.apple.com) satisfy all of the criteria above. + +###### Trusted root certificates + +Since generating a collection signature requires a certificate, part of the signature check involves validating the certificate and its chain and making sure that the root certificate is trusted. + +On Apple platforms, all root certificates that come preinstalled with the OS are automatically trusted. +Users may include additional certificates to trust by placing them in the `~/.swiftpm/config/trust-root-certs` directory. + +On non-Apple platforms, there are no trusted root certificates by default other than those shipped with the [certificate-pinning configuration](). +Only those found in `~/.swiftpm/config/trust-root-certs` are trusted. +This means that the signature check will always fail unless the `trust-root-certs` directory is set up. + +Users can explicitly specify they trust a publisher and any collections they publish, by obtaining that publisher's root certificate and saving it to `~/.swiftpm/config/trust-root-certs`. +The root certificates must be DER-encoded. +Since the package manager trusts all certificate chains under a root, depending on what roots are installed, some publishers may already be trusted implicitly and users don't need to explicitly specify each one. + +With the `package-collection-sign` tool, the root certificate provided as input for signing a collection is automatically trusted. +When a package manager user tries to add the collection, however, the root certificate must either be preinstalled with the OS (Apple platforms only) or found in the `~/.swiftpm/config/trust-root-certs` directory (all platforms) or shipped with the [certificate-pinning configuration](), otherwise the [signature check]() fails. Collection publishers should make the DER-encoded root certificate(s) that they use downloadable so that users can adjust their setup if needed. diff --git a/Sources/PackageManagerDocs/Documentation.docc/RegistryServerSpecification.md b/Sources/PackageManagerDocs/Documentation.docc/RegistryServerSpecification.md new file mode 100644 index 00000000000..5a69389ad75 --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/RegistryServerSpecification.md @@ -0,0 +1,1391 @@ +# Swift Package Registry Service Specification + +Learn about the specification for SwiftPM's registry service. + +### 1. Notations + +The following terminology and conventions are used in this document. + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" +in this document are to be interpreted as described in [RFC 2119]. + +This specification uses the Augmented Backus-Naur Form (ABNF) notation +as described in [RFC 5234] +and Unicode regular expression syntax +as described in [Unicode Technical Standard #18][UAX18]. + +API endpoints that accept parameters in their path +are expressed by Uniform Resource Identifier (URI) templates, +as described in [RFC 6570]. + +### 2. Definitions + +The following terms, as used in this document, have the meanings indicated. + +- _Package_: + A named collection of Swift source code + that is organized into one or more modules + according to a `Package.swift` manifest file. +- _Scope_: + A logical grouping of related packages assigned by a package registry. +- _Release_: + The state of a package after applying a particular set of changes + that is uniquely identified by an assigned version number. +- _Version Number_: + An identifier for a package release + in accordance with the [Semantic Versioning Specification (SemVer)][SemVer]. +- _Precedence_: + The ordering of version numbers relative to each other + as defined by the [Semantic Versioning Specification (SemVer)][SemVer]. + +### 3. Conventions + +This document uses the following conventions +in its description of client-server interactions. + +#### 3.1. Application layer protocols + +A client and server MUST communicate over a secured connection +using Transport Layer Security (TLS) with the `https` URI scheme. + +The use of HTTP 1.1 in examples is non-normative. +A client and server MAY communicate according to this specification +using any version of the HTTP protocol. + +#### 3.2. Authentication + +A server MAY require authentication +for client requests to access information about packages and package releases. + +A server SHOULD respond with a status code of `401` (Unauthorized) +if a client sends a request to an endpoint that requires authentication +without providing credentials. +A server MAY respond with a status code of `404` (Not Found) or `403` (Forbidden) +when a client provides valid credentials +but isn't authorized to access the requested resource. + +A server MAY use any authentication model of its choosing. +However, the use of a scoped, revocable authorization framework +like [OAuth 2.0][RFC 6749] is RECOMMENDED. + +#### 3.3. Error handling + +A server MUST communicate any errors to the client +using "problem details" objects, +as described by [RFC 7807]. +For example, +a client sends a request for a nonexistent release of a package +and receives the following response: + +```http +HTTP/1.1 404 +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en + +{ + "detail": "release not found" +} +``` + +#### 3.4. Rate limiting + +A server MAY limit the number of requests made by a client +by responding with a status code of `429` (Too Many Requests). + +```http +HTTP/1.1 429 +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en +Retry-After: 60 + +{ + "detail": "try again in 60 seconds" +} +``` + +A client SHOULD follow the guidance of any +`Retry-After` header values provided in responses +to prevent overwhelming a server with retry requests. +It is RECOMMENDED for clients to introduce random jitter in their retry logic +to avoid a [thundering herd effect]. + +#### 3.5. API versioning + +Package registry APIs are versioned. + +API version numbers are designated by decimal integers. +The accepted version of this proposal constitutes the initial version, `1`. +Subsequent revisions SHOULD be numbered sequentially +(`2`, `3`, and so on). + +API version numbers SHOULD follow +Semantic Versioning conventions for major releases. +Non-breaking changes, such as +adding new endpoints, +adding new optional parameters to existing endpoints, +or adding new information to existing endpoints in a backward-compatible way, +SHOULD NOT require a new version. +Breaking changes, such as +removing or changing an existing endpoint +in a backward-incompatible way, +MUST correspond to a new version. + +A client SHOULD set the `Accept` header field +to specify the API version of a request. + +```http +GET /mona/LinkedList/list HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1+json +``` + +Valid `Accept` header field values are described by the following rules: + +```abnf + version = "1" ; The API version + mediatype = "json" / ; JSON (default media type) + "zip" / ; Zip archives, used for package releases + "swift" ; Swift file, used for package manifest + accept = "application/vnd.swift.registry" [".v" version] ["+" mediatype] +``` + +A server MUST set the `Content-Type` header field +with the corresponding content type of the response. + +A server MUST set the `Content-Version` header field +with the API version number of the response, unless +explicitly stated otherwise. + +```http +HTTP/1.1 200 OK +Content-Type: application/json +Content-Version: 1 +``` + +If a client sends a request without an `Accept` header, +a server MAY either respond with a status code of `400 Bad Request` or +process the request using an API version that it chooses, +making sure to set the `Content-Type` and `Content-Version` headers accordingly. + +If a client sends a request with an `Accept` header +that specifies an unknown or invalid API version, +a server SHOULD respond with a status code of `400` (Bad Request). + +```http +HTTP/1.1 400 Bad Request +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en + +{ + "detail": "invalid API version" +} +``` + +If a client sends a request with an `Accept` header +that specifies a valid but unsupported API version, +a server SHOULD respond with a status code of `415` (Unsupported Media Type). + +```http +HTTP/1.1 415 Unsupported Media Type +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en + +{ + "detail": "unsupported API version" +} +``` + +#### 3.6. Package identification + +A package may declare external packages as dependencies in its manifest. +Each package dependency may specify a requirement +on which versions are allowed. + +An external package dependency may itself have +one or more external package dependencies, +known as transitive dependencies. +When multiple packages have dependencies in common, +Swift Package Manager determines which version of that package should be used +(if any exist that satisfy all specified requirements) +in a process called package resolution. + +Each external package is uniquely identified +by a scoped identifier in the form `scope.package-name`. + +##### 3.6.1 Package scope + +A *scope* provides a namespace for related packages within a package registry. +A package scope consists of alphanumeric characters and hyphens. +Hyphens may not occur at the beginning or end, +nor consecutively within a scope. +The maximum length of a package scope is 39 characters. +A valid package scope matches the following regular expression pattern: + +```regexp +\A[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}\z +``` + +Package scopes are case-insensitive +(for example, `mona` ≍ `MONA`). + +##### 3.6.2. Package name + +A package's *name* uniquely identifies a package in a scope. +A package name consists of alphanumeric characters, underscores, and hyphens. +Hyphens and underscores may not occur at the beginning or end, +nor consecutively within a name. +The maximum length of a package name is 100 characters. +A valid package name matches the following regular expression pattern: + +```regexp +\A[a-zA-Z0-9](?:[a-zA-Z0-9]|[-_](?=[a-zA-Z0-9])){0,99}\z +``` + +Package names are case-insensitive +(for example, `LinkedList` ≍ `LINKEDLIST`). + +### 4. Endpoints + +A server MUST respond to the following endpoints: + +| Link | Method | Path | Description | +| -------------------- | ------ | --------------------------------------------------------- | ------------------------------------------------- | +| [\[1\]]() | `GET` | `/{scope}/{name}` | List package releases | +| [\[2\]]() | `GET` | `/{scope}/{name}/{version}` | Fetch metadata for a package release | +| [\[3\]]() | `GET` | `/{scope}/{name}/{version}/Package.swift{?swift-version}` | Fetch manifest for a package release | +| [\[4\]]() | `GET` | `/{scope}/{name}/{version}.zip` | Download source archive for a package release | +| [\[5\]]() | `GET` | `/identifiers{?url}` | Lookup package identifiers registered for a URL | +| [\[6\]]() | `PUT` | `/{scope}/{name}/{version}` | Create a package release | + +A server SHOULD also respond to `HEAD` requests +for each of the specified endpoints. + +A client MAY send an `OPTIONS` request with an asterisk (`*`) +to determine the permitted communication options for the server. +A server MAY respond with a `Link` header containing +an entry for the `service-doc` relation type +with a link to this document, and +an entry for the `service-desc` relation type +with a link to the OpenAPI specification. + +* * * + + + +#### 4.1. List package releases + +A client MAY send a `GET` request +for a URI matching the expression `/{scope}/{name}` +to retrieve a list of the available releases for a particular package. +A client SHOULD set the `Accept` header with the value +`application/vnd.swift.registry.v1+json` +and MAY append the `.json` extension to the requested URI. + +```http +GET /mona/LinkedList HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1+json +``` + +If a package is found at the requested location, +a server SHOULD respond with a status code of `200` (OK) +and the `Content-Type` header `application/json`. +Otherwise, a server SHOULD respond with a status code of `404` (Not Found). + +A server SHOULD respond with a JSON document +containing the releases for the requested package. + +```http +HTTP/1.1 200 OK +Content-Type: application/json +Content-Version: 1 +Content-Length: 508 +Link: ; rel="canonical", + ; rel="alternate", + ; rel="latest-version", + ; rel="payment" + +{ + "releases": { + "1.1.1": { + "url": "https://packages.example.com/mona/LinkedList/1.1.1" + }, + "1.1.0": { + "url": "https://packages.example.com/mona/LinkedList/1.1.0", + "problem": { + "status": 410, + "title": "Gone", + "detail": "this release was removed from the registry" + } + }, + "1.0.0": { + "url": "https://packages.example.com/mona/LinkedList/1.0.0" + } + } +} +``` + +The response body MUST contain a JSON object +nested at a top-level `releases` key, +whose keys are version numbers for releases and +whose values are objects containing the following fields: + +| Key | Type | Description | Requirement Level | +| --------- | ------ | ------------------------------------- | ----------------- | +| `url` | String | The location of the release resource. | OPTIONAL | +| `problem` | Object | A [problem details][RFC 7807] object. | OPTIONAL | + +A server MAY specify a URL for a release using the `url` key. +A client SHOULD locate a release using the value of the `url` key, if one is provided. +Otherwise, the client SHOULD locate a release +by expanding the URI Template `/{scope}/{name}/{version}` on the originating host. + +A server SHOULD communicate the unavailability of a package release +using a ["problem details"][RFC 7807] object. +A client SHOULD consider any releases with an associated `problem` +to be unavailable for the purposes of package resolution. + +A server SHOULD respond with +a link to the highest precedence published release of the package if one exists, +using a `Link` header field with a `latest-version` relation. + +A server SHOULD list releases in order of precedence, +starting with the highest precedence version. +However, a client SHOULD NOT assume +any specific ordering of versions in a response. + +A server MAY include a `Link` entry +with the `canonical` relation type +that locates the source repository of the package. + +A server MAY include one or more `Link` entries +with the `alternate` relation type +for other source repository locations. + +A server MAY paginate results by responding with +a `Link` header field that includes any of the following relations: + +| Name | Description | +| ------- | --------------------------------------- | +| `next` | The immediate next page of results. | +| `last` | The last page of results. | +| `first` | The first page of results. | +| `prev` | The immediate previous page of results. | + +For example, +the `Link` header field in a response for the third page of paginated results: + +```http +Link: ; rel="latest-version", + ; rel="first", + ; rel="previous", + ; rel="next", + ; rel="last" +``` + +A server MAY respond with additional `Link` entries, +such as one with a `payment` relation for sponsoring a package maintainer. + + + +#### 4.2. Fetch information about a package release + +A client MAY send a `GET` request +for a URI matching the expression `/{scope}/{name}/{version}` +to retrieve information about a release. +A client SHOULD set the `Accept` header with the value +`application/vnd.swift.registry.v1+json`, +and MAY append the `.json` extension to the requested URI. + +```http +GET /mona/LinkedList/1.1.1 HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1+json +``` + +If a release is found at the requested location, +a server SHOULD respond with a status code of `200` (OK) +and the `Content-Type` header `application/json`. +Otherwise, a server SHOULD respond with a status code of `404` (Not Found). + +```http +HTTP/1.1 200 OK +Content-Version: 1 +Content-Type: application/json +Content-Length: 720 +Link: ; rel="latest-version", + ; rel="predecessor-version" +{ + "id": "mona.LinkedList", + "version": "1.1.1", + "resources": [ + { + "name": "source-archive", + "type": "application/zip", + "checksum": "a2ac54cf25fbc1ad0028f03f0aa4b96833b83bb05a14e510892bb27dea4dc812", + "signing": { + "signatureBase64Encoded": "l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw==", + "signatureFormat": "cms-1.0.0" + } + } + ], + "metadata": { ... }, + "publishedAt": "2023-02-16T04:00:00.000Z" +} +``` + +The response body SHOULD contain a JSON object containing the following fields: + +| Key | Type | Description | Required | +| ------------- | ------ | ----------------------------------------- | :------: | +| `id` | String | The namespaced package identifier. | ✓ | +| `version` | String | The package release version number. | ✓ | +| `resources` | Array | The resources available for the release. | ✓ | +| `metadata` | Object | Additional information about the release. | ✓ | +| `publishedAt` | String | The [ISO 8601]-formatted datetime string of when the package release was published, as recorded by the registry. See related [`originalPublicationTime`]() in `metadata`. | | + +A server SHOULD respond with a `Link` header containing the following entries: + +| Relation | Description | +| --------------------- | ------------------------------------------------------------------------------------ | +| `latest-version` | The highest precedence published release of the package | +| `successor-version` | The next published release of the package ordered by precedence, if one exists | +| `predecessor-version` | The previously published release of the package ordered by precedence, if one exists | + +A link with the `latest-version` relation +MAY correspond to the requested release. + +##### 4.2.1. Package release resources + +Each element in the `resources` array is a JSON object with the following keys: + +| Key | Type | Description | +| ---------- | ------- | -------------------------------------------------------------------------- | +| `name` | String | The name of the resource. | +| `type` | String | The content type of the resource. | +| `checksum` | String | A hexadecimal representation of the SHA256 digest for the resource. | +| `signing` | Object | Information about the signature. Required only if the resource is signed. | + +The `signing` JSON object contains these keys: + +| Key | Type | Description | +| ------------------------ | ------- | ------------------------------------------------- | +| `signatureBase64Encoded` | String | The resource's signature, base64 encoded. | +| `signatureFormat` | String | The signature format. (e.g., `cms-1.0.0`) | + +A resource object SHOULD have one of the following combinations of +`name` and `type` values: + +| Name | Content Type | Description | +| ------------------ | ----------------- | ---------------------------------- | +| `source-archive` | `application/zip` | An archive of package sources. | + +A release MUST NOT have more than a single resource object +with a given combination of `name` and `type` values. + +##### 4.2.2. Package release metadata standards + + [Appendix B]() + defines the JSON schema for package release metadata that + gets submitted as part of the ["create a package release"]() + request. A server MAY allow and/or populate additional metadata by + expanding the schema. The `metadata` key in the + ["fetch information about a package release"]() API response + will hold the user-provided as well as the server populated metadata. + + + +#### 4.3. Fetch manifest for a package release + +A client MAY send a `GET` request for a URI matching the expression +`/{scope}/{name}/{version}/Package.swift` +to retrieve the package manifest for a release. +A client SHOULD set the `Accept` header with the value +`application/vnd.swift.registry.v1+swift`. + +```http +GET /mona/LinkedList/1.1.1/Package.swift HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1+swift +``` + +If a release is found at the requested location, +a server SHOULD respond with a status code of `200` (OK) +and the `Content-Type` header `text/x-swift`. +Otherwise, a server SHOULD respond with a status code of `404` (Not Found). + +```http +HTTP/1.1 200 OK +Cache-Control: public, immutable +Content-Type: text/x-swift +Content-Disposition: attachment; filename="Package.swift" +Content-Length: 361 +Content-Version: 1 +Link: ; rel="alternate"; filename="Package@swift-4.swift"; swift-tools-version="4.0", + ; rel="alternate"; filename="Package@swift-4.2.swift"; swift-tools-version="4.2" + +// swift-tools-version:5.0 +import PackageDescription + +let package = Package( + name: "LinkedList", + products: [ + .library(name: "LinkedList", targets: ["LinkedList"]) + ], + targets: [ + .target(name: "LinkedList"), + .testTarget(name: "LinkedListTests", dependencies: ["LinkedList"]), + ], + swiftLanguageVersions: [.v4, .v5] +) +``` + +A server SHOULD respond with a `Content-Length` header +set to the size of the manifest in bytes. + +A server SHOULD respond with a `Content-Disposition` header +set to `attachment` with a `filename` parameter equal to +the name of the manifest file +(for example, "Package.swift"). + +A server MAY omit the `Content-Version` header +since the response content (i.e., the manifest) SHOULD NOT +change across different API versions. + +It is RECOMMENDED for clients and servers to support +caching as described by [RFC 7234]. + +A server MUST include a `Link` header field +with a value for each version-specific package manifest file +in the release's source archive, +whose filename matches the following regular expression pattern: + +```regexp +\APackage@swift-(\d+)(?:\.(\d+))?(?:\.(\d+))?.swift\z +``` + +Each link value SHOULD have the `alternate` relation type, +a `filename` attribute set to the version-specific package manifest filename +(for example, `Package@swift-4.swift`), and +a `swift-tools-version` attribute set to the [Swift tools version] +specified by the package manifest file +(for example, `4.0` for a manifest beginning with the comment +`// swift-tools-version:4.0`). + +##### 4.3.1. swift-version query parameter + +A client MAY specify a `swift-version` query parameter +to request a manifest for a particular version of Swift. + +```http +GET /mona/LinkedList/1.1.1/Package.swift?swift-version=4.2 HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1+swift +``` + +If the package includes a file named +`Package@swift-{swift-version}.swift`, +the server SHOULD respond with a status code of `200` (OK) +and the content of that file in the response body. + +```http +HTTP/1.1 200 OK +Cache-Control: public, immutable +Content-Type: text/x-swift +Content-Disposition: attachment; filename="Package@swift-4.2.swift" +Content-Length: 361 +Content-Version: 1 + +// swift-tools-version:4.2 +import PackageDescription + +let package = Package( + name: "LinkedList", + products: [ + .library(name: "LinkedList", targets: ["LinkedList"]) + ], + targets: [ + .target(name: "LinkedList"), + .testTarget(name: "LinkedListTests", dependencies: ["LinkedList"]), + ], + swiftLanguageVersions: [.v3, .v4] +) +``` + +Otherwise, +the server SHOULD respond with a status code of `303` (See Other) +and redirect to the unqualified `Package.swift` resource. + +```http +HTTP/1.1 303 See Other +Content-Version: 1 +Location: https://packages.example.com/mona/LinkedList/1.1.1/Package.swift +``` + + + +#### 4.4. Download source archive + +A client MAY send a `GET` request +for a URI matching the expression `/{scope}/{name}/{version}.zip` +to retrieve a release's source archive. +A client SHOULD set the `Accept` header with the value +`application/vnd.swift.registry.v1+zip` +and MUST append the `.zip` extension to the requested path. + +```http +GET /mona/LinkedList/1.1.1.zip HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1+zip +``` + +If a release is found at the requested location, +a server SHOULD respond with a status code of `200` (OK) +and the `Content-Type` header `application/zip`. +Otherwise, a server SHOULD respond with a status code of `404` (Not Found). + +```http +HTTP/1.1 200 OK +Accept-Ranges: bytes +Cache-Control: public, immutable +Content-Type: application/zip +Content-Disposition: attachment; filename="LinkedList-1.1.1.zip" +Content-Length: 2048 +Content-Version: 1 +Digest: sha-256=oqxUzyX7wa0AKPA/CqS5aDO4O7BaFOUQiSuyfepNyBI= +Link: ; rel=duplicate; geo=jp; pri=10; type="application/zip" +X-Swift-Package-Signature-Format: cms-1.0.0 +X-Swift-Package-Signature: l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw== +``` + +A server MUST respond with a `Content-Length` header +set to the size of the archive in bytes. +A client SHOULD terminate any requests whose response exceeds +the expected content length. + +A server MAY respond with a `Digest` header +containing a cryptographic digest of the source archive. + +A server SHOULD respond with a `Content-Disposition` header +set to `attachment` with a `filename` parameter equal to the name of the package +followed by a hyphen (`-`), the version number, and file extension +(for example, "LinkedList-1.1.1.zip"). + +A server MAY omit the `Content-Version` header +since the response content (i.e., the source archive) SHOULD NOT +change across different API versions. + +It is RECOMMENDED for clients and servers to support +range requests as described by [RFC 7233] +and caching as described by [RFC 7234]. + +If a release is signed, a server MUST include +`X-Swift-Package-Signature-Format` and `X-Swift-Package-Signature` +headers in the response. + +##### 4.4.1. Integrity verification + +A client MUST verify the integrity of a downloaded source archive using +the `checksum` value for the associated `source-archive` resource +in the response to `GET /{scope}/{name}/{version}`, +as described in [4.2.1](). + +A client SHOULD also verify the integrity using any values +provided in the `Digest` header of the source archive response +(for using the command +`shasum -b -a 256 LinkedList-1.1.1.zip | cut -f1 | xxd -r -p | base64`). + +##### 4.4.2. Download locations + +A server MAY specify mirrors or multiple download locations +using `Link` header fields +with a `duplicate` relation, +as described by [RFC 6249]. +A client MAY use this information +to determine its preferred strategy for downloading. + +A server MAY respond with a status code of `303` (See Other) +to redirect the client to download the source archive from another host. +The client MUST NOT follow redirects that downgrade to an insecure connection. +The client SHOULD limit the number of redirects to prevent a redirect loop. + +For example, +a server redirects the client to download from +a content delivery network (CDN) using a signed URL: + +```http +HTTP/1.1 303 See Other +Location: https://example.cdn.com/LinkedList-1.1.1.zip?key=XXXXXXXXXXXXXXXXX +``` + +```http +GET /LinkedList-1.1.1.zip?key=XXXXXXXXXXXXXXXXX HTTP/1.1 +Host: example.cdn.com +Accept: application/vnd.swift.registry.v1+zip +``` + +```http +HTTP/1.1 200 OK +Accept-Ranges: bytes +Cache-Control: public, immutable +Content-Type: application/zip +Content-Disposition: attachment; filename="LinkedList-1.1.1.zip" +Content-Length: 2048 +Content-Version: 1 +Digest: sha-256=a2ac54cf25fbc1ad0028f03f0aa4b96833b83bb05a14e510892bb27dea4dc812 +``` + +##### 4.4.3. Signature validation + +A client MUST validate the signature of a signed archive +according to the signature format and configuration. Signing +information can alternatively be found in the associated +`source-archive` resource in the response to `GET /{scope}/{name}/{version}`, +as described in [4.2.1](). + + + +#### 4.5. Lookup package identifiers registered for a URL + +A client MAY send a `GET` request +for a URI matching the expression `/identifiers?url={url}` +to retrieve package identifiers associated with a particular URL. +A client SHOULD set the `Accept` header with the value +`application/vnd.swift.registry.v1+json`. + +```http +GET /identifiers?url=https://github.com/mona/LinkedList HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1 +``` + +A client MUST provide a URL for the `url` query parameter. +When no `url` parameter is specified, +a server SHOULD respond with a status code of `400` (Bad Request). + +If one or more package identifiers are associated with the specified URL, +a server SHOULD respond with a status code of `200` (OK) +and the `Content-Type` header `application/json`. +Otherwise, a server SHOULD respond with a status code of `404` (Not Found). + +A server SHOULD respond with a JSON document +containing the package identifiers for the specified URL. + +```http +HTTP/1.1 200 OK +Content-Type: application/json +Content-Version: 1 + +{ + "identifiers": [ + "mona.LinkedList" + ] +} +``` + +The response body MUST contain an array of package identifier strings +nested at a top-level `identifiers` key. + +It is RECOMMENDED for clients and servers to support +caching as described by [RFC 7234]. + +##### 4.5.1 URL to package identifier mappings + +As part of the [package release metadata]() JSON object, the `repositoryURLs` array can be used to specify URLs associated with a package identifier. +This is one way through which a server can obtain URL to package identifier mappings for this API. + +A server MAY choose other mechanism(s) for package authors to specify these mappings. + +A server SHOULD validate the package author's ownership claim on the corresponding repository. + + + +#### 4.6. Create a package release + +A client MAY send a `PUT` request +for a URI matching the expression +`/{scope}/{name}/{version}` +to publish a release of a package. +A client MUST provide a body encoded as multipart form data +with the following sections: + +| Key | Content-Type | Description | Requirement Level | +| -------------------------- | -------------------------- | ----------------------------------------- | ----------------- | +| `source-archive` | `application/zip` | The source archive of the package. | REQUIRED | +| `source-archive-signature` | `application/octet-stream` | The signature of the source archive. | OPTIONAL | +| `metadata` | `application/json` | Additional information about the release. | OPTIONAL | +| `metadata-signature` | `application/octet-stream` | The signature of the metadata. | OPTIONAL | + +A client MUST set a `Content-Type` header with the value +`multipart/form-data`. `boundary` can be any string. + +A client MAY use any valid value (e.g., `binary`) for the +`Content-Transfer-Encoding` header. + +A client SHOULD set the `Content-Length` header with +the total size of the body in bytes. + +A client SHOULD set the `Accept` header with the value +`application/vnd.swift.registry.v1+json`. + +A client MUST set a `X-Swift-Package-Signature-Format` header +with the signature format if the source archive is signed. + +```http +PUT /mona/LinkedList/1.1.1 HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1+json +Content-Type: multipart/form-data;boundary="boundary" +Content-Length: 336 +Expect: 100-continue +X-Swift-Package-Signature-Format: cms-1.0.0 + +--boundary +Content-Disposition: form-data; name="source-archive" +Content-Type: application/zip +Content-Length: 32 +Content-Transfer-Encoding: base64 + +gHUFBgAAAAAAAAAAAAAAAAAAAAAAAA== + +--boundary +Content-Disposition: form-data; name="source-archive-signature" +Content-Type: application/octet-stream +Content-Length: 88 +Content-Transfer-Encoding: base64 + +l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw== + +--boundary +Content-Disposition: form-data; name="metadata" +Content-Type: application/json +Content-Transfer-Encoding: quoted-printable +Content-Length: 3 + +{ "repositoryURLs": [] } + +--boundary +Content-Disposition: form-data; name="metadata-signature" +Content-Type: application/octet-stream +Content-Length: 88 +Content-Transfer-Encoding: base64 + +M6TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw== + +``` + +A server SHOULD require a client to perform authentication +for any requests to create a package release. +Use of multi-factor authentication is RECOMMENDED. + +A client MAY publish releases in any order. +For example, +if a package has existing `1.0.0` and `2.0.0` releases, +a client MAY publish a new `1.0.1` or `1.1.0` release. + +Once a release has been published, +any resources associated with that release, +including its source archive, +MUST NOT change. + +If a release already exists for a package at the specified version, +the server SHOULD respond with a status code of `409` (Conflict). + +```http +HTTP/1.1 409 Conflict +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en + +{ + "detail": "a release with version 1.0.0 already exists" +} +``` + +It is RECOMMENDED that a server institute policies +for publishing new releases of a package +after a scope is transferred to a new owner. +For example, +the next release of an existing package is published with a new major version, +or only after a period of 45 days after transfer. + +If the client provides an `Expect` header, +a server SHOULD check that the request can succeed +before responding with a status code of `100 (Continue)`. +A server that doesn't support expectations +SHOULD respond with a status code of `417 (Expectation Failed)`. +In response, +a client MAY remove the `Expect` header and retry the request. + +```http +HTTP/1.1 417 (Expectation Failed) +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en + +{ + "detail": "expectations aren't supported" +} +``` + +Support for this endpoint is OPTIONAL. +A server SHOULD indicate that publishing isn't supported +by responding with a status code of `405` (Method Not Allowed). + +```http +HTTP/1.1 405 (Method Not Allowed) +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en + +{ + "detail": "publishing isn't supported" +} +``` + +A server MAY respond either synchronously or asynchronously. +For more information, +see [4.6.3](). + +##### 4.6.1. Source archive + +A client MUST include a multipart section named `source-archive` +containing the source archive for a release. +A client SHOULD set a `Content-Type` header with the value `application/zip` +and a `Content-Length` header with the size of the Zip archive in bytes. + +```http +--boundary +Content-Disposition: form-data; name="source-archive" +Content-Type: application/zip +Content-Length: 32 +Content-Transfer-Encoding: base64 + +gHUFBgAAAAAAAAAAAAAAAAAAAAAAAA== +``` + +A client SHOULD use the `swift package archive-source` tool +to create a source archive for the release. + +A server MAY analyze a package to +assess its viability, +perform security testing, +or otherwise evaluate software quality. +A server MAY refuse to publish a package release for any reason +by responding with a status code of `422` (Unprocessable Entity). + +```http +HTTP/1.1 422 Unprocessable Entity +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en + +{ + "detail": "package doesn't contain a valid manifest (Package.swift) file" +} +``` + +A server SHOULD use the `swift package compute-checksum` tool to compute the checksum that's provided in response to a client's subsequent request to [download the source archive]() for the release. + +##### 4.6.2. Package release metadata + +A client MAY include a multipart section named `metadata` +containing additional information about the release. +A client SHOULD set a `Content-Type` header with the value `application/json` +and a `Content-Length` header with the size of the JSON document in bytes. +The package release metadata MUST be based on the [JSON schema](), +as discussed in [4.2.2](). + +```http +--boundary +Content-Disposition: form-data; name="metadata" +Content-Type: application/json +Content-Length: 226 +Content-Transfer-Encoding: quoted-printable + +{ + "description": "One thing links to another.", + "repositoryURLs": ["https://github.com/mona/LinkedList"], + "licenseURL": "https://www.apache.org/licenses/LICENSE-2.0", + "author": { + "name": "Mona Lisa Octocat" + } +} + +``` + +A server MAY allow and/or populate additional metadata for a release. + +A server MAY make any properties in the [JSON schema]() +and additional metadata it defines required. + +If a client provides an invalid JSON document, +the server SHOULD respond with a status code of +`422` (Unprocessable Entity) or `413` (Payload Too Large) +and MAY communicate validation error details in the response body. + +```http +HTTP/1.1 422 Unprocessable Entity +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en + +{ + "detail": "invalid JSON provided for release metadata" +} +``` + +##### 4.6.3. Synchronous and asynchronous publication + +A server MAY respond to a request to publish a new package release +either synchronously or asynchronously. + +A client MAY indicate their preference for asynchronous processing +with a `Prefer` header field containing the token `respond-async` +and an optional `wait` preference, +as described by [RFC 7240]. + +```http +PUT /mona/LinkedList/1.1.1 HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1 +Prefer: respond-async, wait=300 +``` + +###### 4.6.3.1. Synchronous publication + +If processing is done synchronously, +the server MUST respond with a status code of `201` (Created) +to indicate that the package release was published. +This response SHOULD also contain +a `Location` header with a URL to the new release. + +```http +HTTP/1.1 201 Created +Content-Version: 1 +Location: https://packages.example.com/github.com/mona/LinkedList/1.1.1 +``` + +A client MAY set a timeout to guarantee a timely response to each request. + +###### 4.6.3.2. Asynchronous publication + +If processing is done asynchronously, +the server MUST respond with a status code of `202` (Accepted) +to acknowledge that the request is being processed. +This response MUST contain a `Location` header +with a URL that the client can poll for progress updates +and SHOULD contain a `Retry-After` header +with an estimate of when processing is expected to finish. +A server MAY locate the status resource endpoint at a URI of its choosing. +However, +the use of a non-sequential, randomly-generated identifier is RECOMMENDED. + +```http +HTTP/1.1 202 Accepted +Content-Version: 1 +Location: https://packages.example.com/submissions/90D8CC77-A576-47AE-A531-D6402C4E33BC +Retry-After: 120 +``` + +A client MAY send a `GET` request +to the location provided by the server in response to a publish request +to see the current status of that process. + +```http +GET /submissions/90D8CC77-A576-47AE-A531-D6402C4E33BC HTTP/1.1 +Host: packages.example.com +Accept: application/vnd.swift.registry.v1 +``` + +If the asynchronous publish request is still processing, +the server SHOULD respond with a status code of `202` (Accepted) and +a `Retry-After` header with an estimate of when processing should finish. +A server MAY include additional details in the response body. + +```http +HTTP/1.1 202 Accepted +Content-Version: 1 +Content-Type: application/json +Retry-After: 120 + +{ + "status": "Processing (2/3 steps complete)", + "steps": { + {"name": "Validate metadata", "status": "complete"}, + {"name": "Verify package manifest", "status": "complete"}, + {"name": "Scan for vulnerabilities", "status": "pending"} + } +} +``` + +If the asynchronous publish request is finished processing successfully, +the server SHOULD respond with a status code of `301` (Moved Permanently) +and a `Location` header with a URL to the package release. + +```http +HTTP/1.1 301 Moved Permanently +Content-Version: 1 +Location: https://packages.example.com/mona/LinkedList/1.1.1 +``` + +If the asynchronous publish request failed, +the server SHOULD respond with an appropriate client error status code (`4xx`). + +```http +HTTP/1.1 400 Bad Request +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en +Location: https://packages.example.com/submissions/90D8CC77-A576-47AE-A531-D6402C4E33BC + +{ + "detail": "invalid package" +} +``` + +A client MAY send a `DELETE` request +to the location provided by the server in response to a publish request +to cancel that process. + +If a request to publish a new package release were to fail, +a server MUST communicate that failure in the same way +if sending an immediate response +as it would if responding to a client polling for status. + +If a client makes a request to publish a package release +to a server that is asynchronously processing a request to publish that release, +the server MUST respond with a status code of `409` (Conflict) + +```http +HTTP/1.1 409 Conflict +Content-Version: 1 +Content-Type: application/problem+json +Content-Language: en +Location: https://packages.example.com/submissions/90D8CC77-A576-47AE-A531-D6402C4E33BC + +{ + "detail": "already processing a request to publish this package version" +} +``` + +If a client makes a request to publish a package release +to a server that finished processing a failed request to publish that release, +the server SHOULD try publishing that release again. +A server MAY refuse to fulfill a subsequent request to publish a package release +by responding with a status code of `409` (Conflict). + +### 5. Normative References + +* [RFC 2119]: Key words for use in RFCs to Indicate Requirement Levels +* [RFC 3230]: Instance Digests in HTTP +* [RFC 3986]: Uniform Resource Identifier (URI): Generic Syntax +* [RFC 3987]: Internationalized Resource Identifiers (IRIs) +* [RFC 5234]: Augmented BNF for Syntax Specifications: ABNF +* [RFC 5843]: Additional Hash Algorithms for HTTP Instance Digests +* [RFC 6249]: Metalink/HTTP: Mirrors and Hashes +* [RFC 6570]: URI Template +* [RFC 7159]: The JavaScript Object Notation (JSON) Data Interchange Format +* [RFC 7230]: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing +* [RFC 7231]: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content +* [RFC 7233]: Hypertext Transfer Protocol (HTTP/1.1): Range Requests +* [RFC 7234]: Hypertext Transfer Protocol (HTTP/1.1): Caching +* [RFC 7240]: Prefer Header for HTTP +* [RFC 7578]: Returning Values from Forms: multipart/form-data +* [RFC 7807]: Problem Details for HTTP APIs +* [RFC 8288]: Web Linking +* [SemVer]: Semantic Versioning + +### 6. Informative References + +* [BCP 13] Media Type Specifications and Registration Procedures +* [RFC 6749]: The OAuth 2.0 Authorization Framework +* [RFC 8446]: The Transport Layer Security (TLS) Protocol Version 1.3 +* [RFC 8631]: Link Relation Types for Web Services +* [JSON-LD]: A JSON-based Serialization for Linked Data +* [Schema.org]: A shared vocabulary for structured data. +* [OAS]: OpenAPI Specification + +### Appendix A - OpenAPI Document + +The following [OpenAPI (v3) specification][OAS] is non-normative, +and is provided for the convenience of +developers interested in building their own package registry. + +See [registry.openapi.yaml](./registry.openapi.yaml). + +### Appendix B - Package Release Metadata JSON Schema + +The `metadata` section of the [create package release request]() +must be a JSON object of type [`PackageRelease`](), as defined in the +JSON schema below. + +
+ +Expand to view JSON schema + +```json +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md", + "title": "Package Release Metadata", + "description": "Metadata of a package release.", + "type": "object", + "properties": { + "author": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the author." + }, + "email": { + "type": "string", + "format": "email", + "description": "Email address of the author." + }, + "description": { + "type": "string", + "description": "A description of the author." + }, + "organization": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the organization." + }, + "email": { + "type": "string", + "format": "email", + "description": "Email address of the organization." + }, + "description": { + "type": "string", + "description": "A description of the organization." + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL of the organization." + }, + }, + "required": ["name"] + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL of the author." + }, + }, + "required": ["name"] + }, + "description": { + "type": "string", + "description": "A description of the package release." + }, + "licenseURL": { + "type": "string", + "format": "uri", + "description": "URL of the package release's license document." + }, + "originalPublicationTime": { + "type": "string", + "format": "date-time", + "description": "Original publication time of the package release in ISO 8601 format." + }, + "readmeURL": { + "type": "string", + "format": "uri", + "description": "URL of the README specifically for the package release or broadly for the package." + }, + "repositoryURLs": { + "type": "array", + "description": "Code repository URL(s) of the package release.", + "items": { + "type": "string", + "description": "Code repository URL." + } + } + } +} +``` + +
+ +###### PackageRelease type + +| Property | Type | Description | Required | +| ------------------------- | :-----------------: | ------------------------------------------------ | :------: | +| `author` | [Author]() | Author of the package release. | | +| `description` | String | A description of the package release. | | +| `licenseURL` | String | URL of the package release's license document. | | +| `originalPublicationTime` | String | Original publication time of the package release in [ISO 8601] format. This can be set if the package release was previously published elsewhere.
A registry should record the publication time independently and include it as `publishedAt` in the [package release metadata response]().
In case both `originalPublicationTime` and `publishedAt` are set, `originalPublicationTime` should be used. | | +| `readmeURL` | String | URL of the README specifically for the package release or broadly for the package. | | +| `repositoryURLs` | Array | Code repository URL(s) of the package. It is recommended to include all URL variations (e.g., SSH, HTTPS) for the same repository. This can be an empty array if the package does not have source control representation.
Setting this property is one way through which a registry can obtain repository URL to package identifier mappings for the ["lookup package identifiers registered for a URL" API](). A registry may choose other mechanism(s) for package authors to specify such mappings. | | + +###### Author type + +| Property | Type | Description | Required | +| ----------------- | :-----------------: | ------------------------------------------------ | :------: | +| `name` | String | Name of the author. | ✓ | +| `email` | String | Email address of the author. | | +| `description` | String | A description of the author. | | +| `organization` | [Organization]() | Organization that the author belongs to. | | +| `url` | String | URL of the author. | | + +###### Organization type + +| Property | Type | Description | Required | +| ----------------- | :-----------------: | ------------------------------------------------ | :------: | +| `name` | String | Name of the organization. | ✓ | +| `email` | String | Email address of the organization. | | +| `description` | String | A description of the organization. | | +| `url` | String | URL of the organization. | | + +[UAX18]: https://unicode.org/reports/tr18/ +[BCP 13]: https://tools.ietf.org/html/rfc6838 "Media Type Specifications and Registration Procedures" +[RFC 2119]: https://tools.ietf.org/html/rfc2119 "Key words for use in RFCs to Indicate Requirement Levels" +[RFC 3230]: https://tools.ietf.org/html/rfc5843 "Instance Digests in HTTP" +[RFC 3986]: https://tools.ietf.org/html/rfc3986 "Uniform Resource Identifier (URI): Generic Syntax" +[RFC 3987]: https://tools.ietf.org/html/rfc3987 "Internationalized Resource Identifiers (IRIs)" +[RFC 5234]: https://tools.ietf.org/html/rfc5234 "Augmented BNF for Syntax Specifications: ABNF" +[RFC 5843]: https://tools.ietf.org/html/rfc5843 "Additional Hash Algorithms for HTTP Instance Digests" +[RFC 6249]: https://tools.ietf.org/html/rfc6249 "Metalink/HTTP: Mirrors and Hashes" +[RFC 6570]: https://tools.ietf.org/html/rfc6570 "URI Template" +[RFC 6749]: https://tools.ietf.org/html/rfc6749 "The OAuth 2.0 Authorization Framework" +[RFC 7159]: https://tools.ietf.org/html/rfc7159 "The JavaScript Object Notation (JSON) Data Interchange Format" +[RFC 7230]: https://tools.ietf.org/html/rfc7230 "Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing" +[RFC 7231]: https://tools.ietf.org/html/rfc7231 "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content" +[RFC 7233]: https://tools.ietf.org/html/rfc7233 "Hypertext Transfer Protocol (HTTP/1.1): Range Requests" +[RFC 7234]: https://tools.ietf.org/html/rfc7234 "Hypertext Transfer Protocol (HTTP/1.1): Caching" +[RFC 7240]: https://tools.ietf.org/html/rfc7240 "Prefer Header for HTTP" +[RFC 7578]: https://tools.ietf.org/html/rfc7578 "Returning Values from Forms: multipart/form-data" +[RFC 7807]: https://tools.ietf.org/html/rfc7807 "Problem Details for HTTP APIs" +[RFC 8288]: https://tools.ietf.org/html/rfc8288 "Web Linking" +[RFC 8446]: https://tools.ietf.org/html/rfc8446 "The Transport Layer Security (TLS) Protocol Version 1.3" +[RFC 8631]: https://tools.ietf.org/html/rfc8631 "Link Relation Types for Web Services" +[IANA Link Relations]: https://www.iana.org/assignments/link-relations/link-relations.xhtml +[JSON-LD]: https://w3c.github.io/json-ld-syntax/ "JSON-LD 1.1: A JSON-based Serialization for Linked Data" +[SemVer]: https://semver.org/ "Semantic Versioning" +[Schema.org]: https://schema.org/ +[SoftwareSourceCode]: https://schema.org/SoftwareSourceCode +[DUST]: https://doi.org/10.1145/1462148.1462151 "Bar-Yossef, Ziv, et al. Do Not Crawl in the DUST: Different URLs with Similar Text. Association for Computing Machinery, 17 Jan. 2009. January 2009" +[OAS]: https://swagger.io/specification/ "OpenAPI Specification" +[GitHub / Swift Package Management Service]: https://forums.swift.org/t/github-swift-package-management-service/30406 +[RubyGems]: https://rubygems.org "RubyGems: The Ruby community’s gem hosting service" +[PyPI]: https://pypi.org "PyPI: The Python Package Index" +[npm]: https://www.npmjs.com "The npm Registry" +[crates.io]: https://crates.io "crates.io: The Rust community’s crate registry" +[CocoaPods]: https://cocoapods.org "A dependency manager for Swift and Objective-C Cocoa projects" +[thundering herd effect]: https://en.wikipedia.org/wiki/Thundering_herd_problem "Thundering herd problem" +[offline cache]: https://yarnpkg.com/features/offline-cache "Offline Cache | Yarn - Package Manager" +[XCFramework]: https://developer.apple.com/videos/play/wwdc2019/416/ "WWDC 2019 Session 416: Binary Frameworks in Swift" +[SE-0272]: https://github.com/swiftlang/swift-evolution/blob/master/proposals/0272-swiftpm-binary-dependencies.md "Package Manager Binary Dependencies" +[Swift tools version]: https://github.com/swiftlang/swift-package-manager/blob/9b9bed7eaf0f38eeccd0d8ca06ae08f6689d1c3f/Documentation/Usage.md#swift-tools-version-specification "Swift Tools Version Specification" +[ISO 8601]: https://www.iso.org/iso-8601-date-and-time-format.html "ISO 8601 Date and Time Format" diff --git a/Sources/PackageManagerDocs/Documentation.docc/UsingSwiftPackageRegistry.md b/Sources/PackageManagerDocs/Documentation.docc/UsingSwiftPackageRegistry.md new file mode 100644 index 00000000000..5704fe78927 --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/UsingSwiftPackageRegistry.md @@ -0,0 +1,310 @@ +# Using a package registry + +Configure and use a package registry for Swift Package Manager. + +## Overview + +Swift Package Manager supports downloading dependencies from any package registry that implements +[SE-0292](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md) +and the corresponding [service specification](). + +In a registry, packages are identified by [package identifier](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md#package-identity) +in the form of `scope.package-name`. + +### Configuring a registry + +A registry can be configured in Swift Package Manager at two levels: + - Project: the registry will be used for packages within the project. Settings are stored in `.swiftpm/configuration/registries.json`. + - User: the registry will be used for all projects for the user. Settings are stored in `~/.swiftpm/configuration/registries.json`. + +One could use the [`swift package-registry set` subcommand]() to assign a registry URL: + +```bash +$ 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: + +```bash +$ swift package-registry set --global https://packages.example.com +``` + +The resulting `registries.json` would look something like: + +```json +{ + "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. + +### Adding a registry package dependency + +A registry package dependency is declared in `Package.swift` using the package identifier. +For example: + +```swift +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. + +### Registry authentication + +If a registry requires authentication, it can be set up by using the [`swift package-registry login`]() subcommand introduced by [SE-0378](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0378-package-registry-auth.md#new-login-subcommand). + +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: + +```bash +$ 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. + +### Dependency Resolution Using Registry + +Resolving a registry dependency involves these steps: +1. Fetch a package's available versions by calling the [list package releases]() API. +2. Compute the dependency graph by [fetching manifest(s) for a package release](). +3. Pinpoint the package version to use. + +For more information on resolving dependencies, see . + +#### Using registry for source control dependencies + +Here is an example of a source control dependency: + +```swift +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. + +### Dependency Download From Registry + +After a registry dependency is resolved, Swift Package Manager can [download source archive]() of the computed package version from the registry. + +#### Package security + +As a security feature, Swift Package Manager performs checksum TOFU ([trust-on-first-use](https://en.wikipedia.org/wiki/Trust_on_first_use)) on the downloaded source archive. See for more information about Package manager's use of trust-on-first-use. + +#### Validating signed packages + + [SE-0391](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md#package-signing) 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 . + +### Publishing to Registry + + [`swift package-registry publish`](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md#new-package-registry-publish-subcommand) is an all-in-one command for publishing a package release to registry. + +#### Package signing + +Registries can optionally require signing. +For more details on signed registry packages, see . + +##### Signature formats + +| Signature Format | Specification | +| ---------------- | ------------- | +| `cms-1.0.0` | [SE-391](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md#package-signature-format-cms-100) | + +Since there is only one supported signature format, all signatures produced by Swift Package Manager are in `cms-1.0.0`. + +##### Signed contents + +###### Source archive + +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. + +###### 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 manifest(s) + +`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 +// 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. + +### Swift Package Manager Registry Configuration + +#### Registry-to-scope mappings + +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: + +```json +// 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 +} +``` + +- For package `foo.LinkedList`, the registry at `https://local.example.com` is used. (Local configuration has higher precedence than user-level configuration.) +- For package `bar.LinkedList`, the registry at `https://global.example.com` is used. (No mapping for scope `bar` is found, so `[default]` is used.) + +#### Security configuration + +Registry security configurations are specified in the user-level `registries.json` (`~/.swiftpm/configuration/registries.json`): + +```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": , + "includeDefaultTrustedRootCertificates": , + "validationChecks": { + "certificateExpiration": "enabled", + "certificateRevocation": "allowSoftFail" + } + } + } + }, + "scopeOverrides": { + // The example shows all configuration overridable at scope level + "mona": { + "signing": { + "trustedRootCertificatesPath": , + "includeDefaultTrustedRootCertificates": + } + } + }, + "packageOverrides": { + // The example shows all configuration overridable at package level + "mona.LinkedList": { + "signing": { + "trustedRootCertificatesPath": , + "includeDefaultTrustedRootCertificates": + } + } + } + }, + ... +} +``` + +There are multiple levels of overrides. +A configuration for a package is computed using values from the following (in descending precedence): +1. `packageOverrides` (if any) +1. `scopeOverrides` (if any) +1. `registryOverrides` (if any) +1. `default` + +The `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.
  • If no, Package manager will reject the package and fail the build.
  • 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.
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.
  • If no, Package manager will reject the package and fail the build.
  • If yes, Package manager will proceed with the package as if it were an unsigned package.
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` |
  • `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.
  • `disabled`: Package manager will not perform this check.
| + | `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](https://www.rfc-editor.org/rfc/rfc6960).
  • `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).
  • `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).
  • `disabled`: Package manager will not perform this check.
|